@defra/forms-engine-plugin 4.7.2 → 4.8.0

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 (407) hide show
  1. package/.public/javascripts/shared.min.js +1 -1
  2. package/.public/javascripts/shared.min.js.map +1 -1
  3. package/.server/client/javascripts/geospatial-map.d.ts +6 -6
  4. package/.server/client/javascripts/geospatial-map.js +3 -3
  5. package/.server/client/javascripts/location-map.d.ts +1 -1
  6. package/.server/client/javascripts/location-map.js +1 -1
  7. package/.server/client/javascripts/map.d.ts +5 -1
  8. package/.server/client/javascripts/map.js +10 -2
  9. package/.server/client/javascripts/map.js.map +1 -1
  10. package/.server/client/javascripts/shared.d.ts +7 -7
  11. package/.server/server/index.d.ts +1 -1
  12. package/.server/server/plugins/crumb.d.ts +1 -1
  13. package/.server/server/plugins/engine/beta/form-context.d.ts +6 -6
  14. package/.server/server/plugins/engine/components/AutocompleteField.d.ts +4 -4
  15. package/.server/server/plugins/engine/components/CheckboxesField.d.ts +2 -2
  16. package/.server/server/plugins/engine/components/CheckboxesField.js +2 -2
  17. package/.server/server/plugins/engine/components/CheckboxesField.js.map +1 -1
  18. package/.server/server/plugins/engine/components/ComponentBase.d.ts +5 -5
  19. package/.server/server/plugins/engine/components/ComponentCollection.d.ts +8 -8
  20. package/.server/server/plugins/engine/components/DatePartsField.d.ts +11 -11
  21. package/.server/server/plugins/engine/components/DeclarationField.d.ts +3 -3
  22. package/.server/server/plugins/engine/components/Details.d.ts +1 -1
  23. package/.server/server/plugins/engine/components/EastingNorthingField.d.ts +22 -22
  24. package/.server/server/plugins/engine/components/EmailAddressField.d.ts +4 -4
  25. package/.server/server/plugins/engine/components/FileUploadField.d.ts +3 -3
  26. package/.server/server/plugins/engine/components/FormComponent.d.ts +10 -10
  27. package/.server/server/plugins/engine/components/GeospatialField.d.ts +6 -6
  28. package/.server/server/plugins/engine/components/HiddenField.d.ts +2 -2
  29. package/.server/server/plugins/engine/components/Html.d.ts +1 -1
  30. package/.server/server/plugins/engine/components/InsetText.d.ts +1 -1
  31. package/.server/server/plugins/engine/components/LatLongField.d.ts +22 -22
  32. package/.server/server/plugins/engine/components/List.d.ts +8 -8
  33. package/.server/server/plugins/engine/components/ListFormComponent.d.ts +10 -10
  34. package/.server/server/plugins/engine/components/LocationFieldBase.d.ts +6 -6
  35. package/.server/server/plugins/engine/components/LocationFieldHelpers.d.ts +14 -14
  36. package/.server/server/plugins/engine/components/Markdown.d.ts +1 -1
  37. package/.server/server/plugins/engine/components/MonthYearField.d.ts +11 -11
  38. package/.server/server/plugins/engine/components/MultilineTextField.d.ts +5 -5
  39. package/.server/server/plugins/engine/components/NationalGridFieldNumberField.d.ts +1 -1
  40. package/.server/server/plugins/engine/components/NumberField.d.ts +3 -3
  41. package/.server/server/plugins/engine/components/OsGridRefField.d.ts +1 -1
  42. package/.server/server/plugins/engine/components/PaymentField.d.ts +12 -12
  43. package/.server/server/plugins/engine/components/RadiosField.d.ts +1 -1
  44. package/.server/server/plugins/engine/components/SelectField.d.ts +4 -4
  45. package/.server/server/plugins/engine/components/SelectionControlField.d.ts +10 -10
  46. package/.server/server/plugins/engine/components/TelephoneNumberField.d.ts +4 -4
  47. package/.server/server/plugins/engine/components/TextField.d.ts +2 -2
  48. package/.server/server/plugins/engine/components/UkAddressField.d.ts +11 -11
  49. package/.server/server/plugins/engine/components/YesNoField.d.ts +2 -2
  50. package/.server/server/plugins/engine/components/helpers/__stubs__/geospatial.d.ts +1 -1
  51. package/.server/server/plugins/engine/components/helpers/components.d.ts +5 -5
  52. package/.server/server/plugins/engine/components/helpers/geospatial.d.ts +1 -1
  53. package/.server/server/plugins/engine/components/index.d.ts +27 -27
  54. package/.server/server/plugins/engine/components/types.d.ts +1 -1
  55. package/.server/server/plugins/engine/configureEnginePlugin.d.ts +4 -4
  56. package/.server/server/plugins/engine/date-helper.d.ts +1 -1
  57. package/.server/server/plugins/engine/helpers.d.ts +8 -8
  58. package/.server/server/plugins/engine/index.d.ts +5 -5
  59. package/.server/server/plugins/engine/models/FormModel.d.ts +6 -6
  60. package/.server/server/plugins/engine/models/SummaryViewModel.d.ts +6 -6
  61. package/.server/server/plugins/engine/models/index.d.ts +2 -2
  62. package/.server/server/plugins/engine/models/types.d.ts +4 -4
  63. package/.server/server/plugins/engine/options.d.ts +1 -1
  64. package/.server/server/plugins/engine/options.js +1 -1
  65. package/.server/server/plugins/engine/options.test.js +1 -1
  66. package/.server/server/plugins/engine/outputFormatters/adapter/v1.d.ts +4 -4
  67. package/.server/server/plugins/engine/outputFormatters/human/v1.d.ts +4 -4
  68. package/.server/server/plugins/engine/outputFormatters/index.d.ts +5 -5
  69. package/.server/server/plugins/engine/outputFormatters/machine/v1.d.ts +4 -4
  70. package/.server/server/plugins/engine/outputFormatters/machine/v2.d.ts +4 -4
  71. package/.server/server/plugins/engine/pageControllers/FileUploadPageController.d.ts +8 -8
  72. package/.server/server/plugins/engine/pageControllers/PageController.d.ts +6 -6
  73. package/.server/server/plugins/engine/pageControllers/QuestionPageController.d.ts +8 -8
  74. package/.server/server/plugins/engine/pageControllers/RepeatPageController.d.ts +5 -5
  75. package/.server/server/plugins/engine/pageControllers/StartPageController.d.ts +4 -4
  76. package/.server/server/plugins/engine/pageControllers/StatusPageController.d.ts +4 -4
  77. package/.server/server/plugins/engine/pageControllers/SummaryPageController.d.ts +5 -5
  78. package/.server/server/plugins/engine/pageControllers/TerminalPageController.d.ts +3 -3
  79. package/.server/server/plugins/engine/pageControllers/__stubs__/request.d.ts +2 -2
  80. package/.server/server/plugins/engine/pageControllers/errors.d.ts +1 -1
  81. package/.server/server/plugins/engine/pageControllers/helpers/pages.d.ts +2 -2
  82. package/.server/server/plugins/engine/pageControllers/helpers/state.d.ts +5 -5
  83. package/.server/server/plugins/engine/pageControllers/helpers/state.js +1 -1
  84. package/.server/server/plugins/engine/pageControllers/helpers/state.js.map +1 -1
  85. package/.server/server/plugins/engine/pageControllers/helpers/submission.d.ts +1 -1
  86. package/.server/server/plugins/engine/pageControllers/index.d.ts +7 -7
  87. package/.server/server/plugins/engine/plugin.d.ts +1 -1
  88. package/.server/server/plugins/engine/routes/file-upload.d.ts +1 -1
  89. package/.server/server/plugins/engine/routes/index.d.ts +3 -3
  90. package/.server/server/plugins/engine/routes/payment-helper.d.ts +3 -3
  91. package/.server/server/plugins/engine/routes/payment-helper.js +2 -2
  92. package/.server/server/plugins/engine/routes/payment.js +5 -5
  93. package/.server/server/plugins/engine/routes/payment.test.js +1 -1
  94. package/.server/server/plugins/engine/routes/questions.d.ts +2 -2
  95. package/.server/server/plugins/engine/routes/repeaters/item-delete.d.ts +2 -2
  96. package/.server/server/plugins/engine/routes/repeaters/summary.d.ts +2 -2
  97. package/.server/server/plugins/engine/services/index.d.ts +3 -3
  98. package/.server/server/plugins/engine/services/notifyService.d.ts +4 -4
  99. package/.server/server/plugins/engine/services/uploadService.d.ts +2 -2
  100. package/.server/server/plugins/engine/services/uploadService.js +1 -1
  101. package/.server/server/plugins/engine/types/index.d.ts +10 -10
  102. package/.server/server/plugins/engine/types/schema.d.ts +1 -1
  103. package/.server/server/plugins/engine/types.d.ts +25 -16
  104. package/.server/server/plugins/engine/types.js.map +1 -1
  105. package/.server/server/plugins/engine/validationHelpers.d.ts +2 -2
  106. package/.server/server/plugins/engine/vision.d.ts +1 -1
  107. package/.server/server/plugins/map/index.d.ts +1 -1
  108. package/.server/server/plugins/map/index.js +1 -1
  109. package/.server/server/plugins/map/routes/get-os-token.d.ts +11 -1
  110. package/.server/server/plugins/map/routes/get-os-token.js +12 -2
  111. package/.server/server/plugins/map/routes/get-os-token.js.map +1 -1
  112. package/.server/server/plugins/map/routes/index.d.ts +4 -4
  113. package/.server/server/plugins/map/routes/index.js +3 -2
  114. package/.server/server/plugins/map/routes/index.js.map +1 -1
  115. package/.server/server/plugins/map/routes/vts/esri-aerial.json +23 -0
  116. package/.server/server/plugins/map/service.d.ts +1 -1
  117. package/.server/server/plugins/map/service.js +5 -2
  118. package/.server/server/plugins/map/service.js.map +1 -1
  119. package/.server/server/plugins/map/test/__stubs__/find.d.ts +1 -1
  120. package/.server/server/plugins/map/test/__stubs__/find.js +1 -1
  121. package/.server/server/plugins/nunjucks/context.d.ts +2 -2
  122. package/.server/server/plugins/nunjucks/context.js +2 -2
  123. package/.server/server/plugins/nunjucks/context.test.js +1 -1
  124. package/.server/server/plugins/nunjucks/enviroment.test.js +1 -1
  125. package/.server/server/plugins/nunjucks/environment.d.ts +3 -3
  126. package/.server/server/plugins/nunjucks/environment.js +3 -3
  127. package/.server/server/plugins/nunjucks/filters/answer.d.ts +1 -1
  128. package/.server/server/plugins/nunjucks/filters/answer.js +2 -2
  129. package/.server/server/plugins/nunjucks/filters/answer.test.js +1 -1
  130. package/.server/server/plugins/nunjucks/filters/evaluate.d.ts +1 -1
  131. package/.server/server/plugins/nunjucks/filters/evaluate.js +1 -1
  132. package/.server/server/plugins/nunjucks/filters/field.d.ts +1 -1
  133. package/.server/server/plugins/nunjucks/filters/field.js +1 -1
  134. package/.server/server/plugins/nunjucks/filters/field.test.js +1 -1
  135. package/.server/server/plugins/nunjucks/filters/href.d.ts +1 -1
  136. package/.server/server/plugins/nunjucks/filters/href.js +1 -1
  137. package/.server/server/plugins/nunjucks/filters/href.test.js +1 -1
  138. package/.server/server/plugins/nunjucks/filters/index.d.ts +8 -8
  139. package/.server/server/plugins/nunjucks/filters/page.d.ts +1 -1
  140. package/.server/server/plugins/nunjucks/filters/page.js +1 -1
  141. package/.server/server/plugins/nunjucks/filters/page.test.js +1 -1
  142. package/.server/server/plugins/nunjucks/index.d.ts +3 -3
  143. package/.server/server/plugins/nunjucks/render.d.ts +2 -2
  144. package/.server/server/plugins/nunjucks/render.js +1 -1
  145. package/.server/server/plugins/nunjucks/types.d.ts +1 -1
  146. package/.server/server/plugins/nunjucks/types.js +1 -1
  147. package/.server/server/plugins/payment/helper.d.ts +2 -2
  148. package/.server/server/plugins/payment/helper.js +1 -1
  149. package/.server/server/plugins/payment/service.d.ts +3 -3
  150. package/.server/server/plugins/payment/service.js +1 -1
  151. package/.server/server/plugins/postcode-lookup/index.d.ts +1 -1
  152. package/.server/server/plugins/postcode-lookup/index.js +1 -1
  153. package/.server/server/plugins/postcode-lookup/models/index.d.ts +6 -6
  154. package/.server/server/plugins/postcode-lookup/models/index.js +1 -1
  155. package/.server/server/plugins/postcode-lookup/routes/index.d.ts +6 -6
  156. package/.server/server/plugins/postcode-lookup/routes/index.js +15 -15
  157. package/.server/server/plugins/postcode-lookup/routes/index.js.map +1 -1
  158. package/.server/server/plugins/postcode-lookup/service.d.ts +1 -1
  159. package/.server/server/plugins/postcode-lookup/service.js +5 -2
  160. package/.server/server/plugins/postcode-lookup/service.js.map +1 -1
  161. package/.server/server/plugins/postcode-lookup/types.js +1 -1
  162. package/.server/server/routes/index.d.ts +2 -2
  163. package/.server/server/routes/types.d.ts +1 -1
  164. package/.server/server/schemas/index.d.ts +2 -2
  165. package/.server/server/services/cacheService.d.ts +8 -8
  166. package/.server/server/services/cacheService.js +2 -5
  167. package/.server/server/services/cacheService.js.map +1 -1
  168. package/.server/server/services/httpService.test.js +1 -1
  169. package/.server/server/services/index.d.ts +1 -1
  170. package/.server/server/types.d.ts +7 -7
  171. package/.server/server/utils/file-form-service.d.ts +2 -2
  172. package/.server/server/utils/file-form-service.js +1 -1
  173. package/package.json +8 -4
  174. package/src/client/javascripts/application.js +1 -1
  175. package/src/client/javascripts/geospatial-map.js +4 -4
  176. package/src/client/javascripts/location-map.js +2 -2
  177. package/src/client/javascripts/map.js +13 -4
  178. package/src/client/javascripts/shared.js +7 -7
  179. package/src/index.ts +3 -3
  180. package/src/server/common/helpers/logging/logger-options.ts +1 -1
  181. package/src/server/common/helpers/logging/logger.ts +1 -1
  182. package/src/server/common/helpers/logging/request-logger.ts +1 -1
  183. package/src/server/common/helpers/logging/request-tracing.js +1 -1
  184. package/src/server/common/helpers/redis-client.js +2 -2
  185. package/src/server/index.ts +13 -13
  186. package/src/server/plugins/crumb.ts +2 -2
  187. package/src/server/plugins/engine/beta/form-context.ts +9 -9
  188. package/src/server/plugins/engine/components/AutocompleteField.ts +3 -3
  189. package/src/server/plugins/engine/components/CheckboxesField.ts +7 -8
  190. package/src/server/plugins/engine/components/ComponentBase.ts +5 -5
  191. package/src/server/plugins/engine/components/ComponentCollection.ts +9 -9
  192. package/src/server/plugins/engine/components/DatePartsField.ts +8 -8
  193. package/src/server/plugins/engine/components/DeclarationField.ts +3 -3
  194. package/src/server/plugins/engine/components/Details.ts +1 -1
  195. package/src/server/plugins/engine/components/EastingNorthingField.ts +9 -9
  196. package/src/server/plugins/engine/components/EmailAddressField.ts +3 -3
  197. package/src/server/plugins/engine/components/FileUploadField.ts +6 -6
  198. package/src/server/plugins/engine/components/FormComponent.ts +4 -4
  199. package/src/server/plugins/engine/components/GeospatialField.ts +5 -5
  200. package/src/server/plugins/engine/components/HiddenField.ts +4 -4
  201. package/src/server/plugins/engine/components/Html.ts +1 -1
  202. package/src/server/plugins/engine/components/InsetText.ts +1 -1
  203. package/src/server/plugins/engine/components/LatLongField.ts +9 -9
  204. package/src/server/plugins/engine/components/List.ts +2 -2
  205. package/src/server/plugins/engine/components/ListFormComponent.ts +4 -4
  206. package/src/server/plugins/engine/components/LocationFieldBase.ts +5 -5
  207. package/src/server/plugins/engine/components/LocationFieldHelpers.ts +5 -5
  208. package/src/server/plugins/engine/components/Markdown.ts +1 -1
  209. package/src/server/plugins/engine/components/MonthYearField.ts +8 -8
  210. package/src/server/plugins/engine/components/MultilineTextField.ts +4 -4
  211. package/src/server/plugins/engine/components/NationalGridFieldNumberField.ts +2 -2
  212. package/src/server/plugins/engine/components/NumberField.ts +3 -3
  213. package/src/server/plugins/engine/components/OsGridRefField.ts +2 -2
  214. package/src/server/plugins/engine/components/PaymentField.ts +8 -8
  215. package/src/server/plugins/engine/components/RadiosField.ts +1 -1
  216. package/src/server/plugins/engine/components/SelectField.ts +2 -2
  217. package/src/server/plugins/engine/components/SelectionControlField.ts +4 -4
  218. package/src/server/plugins/engine/components/TelephoneNumberField.ts +4 -4
  219. package/src/server/plugins/engine/components/TextField.ts +3 -3
  220. package/src/server/plugins/engine/components/UkAddressField.ts +7 -7
  221. package/src/server/plugins/engine/components/YesNoField.ts +5 -5
  222. package/src/server/plugins/engine/components/helpers/__stubs__/geospatial.ts +1 -1
  223. package/src/server/plugins/engine/components/helpers/components.ts +8 -8
  224. package/src/server/plugins/engine/components/helpers/geospatial.ts +1 -1
  225. package/src/server/plugins/engine/components/index.ts +27 -27
  226. package/src/server/plugins/engine/components/types.ts +1 -1
  227. package/src/server/plugins/engine/configureEnginePlugin.ts +10 -10
  228. package/src/server/plugins/engine/date-helper.ts +1 -1
  229. package/src/server/plugins/engine/helpers.ts +8 -8
  230. package/src/server/plugins/engine/index.ts +8 -8
  231. package/src/server/plugins/engine/models/FormModel.ts +15 -15
  232. package/src/server/plugins/engine/models/SummaryViewModel.ts +10 -10
  233. package/src/server/plugins/engine/models/index.ts +2 -2
  234. package/src/server/plugins/engine/models/types.ts +4 -4
  235. package/src/server/plugins/engine/options.js +3 -3
  236. package/src/server/plugins/engine/outputFormatters/adapter/v1.ts +6 -6
  237. package/src/server/plugins/engine/outputFormatters/human/v1.ts +9 -9
  238. package/src/server/plugins/engine/outputFormatters/index.ts +8 -8
  239. package/src/server/plugins/engine/outputFormatters/machine/v1.ts +7 -7
  240. package/src/server/plugins/engine/outputFormatters/machine/v2.ts +6 -6
  241. package/src/server/plugins/engine/pageControllers/FileUploadPageController.ts +9 -9
  242. package/src/server/plugins/engine/pageControllers/PageController.ts +7 -7
  243. package/src/server/plugins/engine/pageControllers/QuestionPageController.ts +13 -13
  244. package/src/server/plugins/engine/pageControllers/RepeatPageController.ts +6 -6
  245. package/src/server/plugins/engine/pageControllers/StartPageController.ts +3 -3
  246. package/src/server/plugins/engine/pageControllers/StatusPageController.ts +5 -5
  247. package/src/server/plugins/engine/pageControllers/SummaryPageController.ts +12 -12
  248. package/src/server/plugins/engine/pageControllers/TerminalPageController.ts +3 -3
  249. package/src/server/plugins/engine/pageControllers/__stubs__/request.ts +3 -3
  250. package/src/server/plugins/engine/pageControllers/__stubs__/server.ts +2 -2
  251. package/src/server/plugins/engine/pageControllers/errors.ts +1 -1
  252. package/src/server/plugins/engine/pageControllers/helpers/pages.ts +2 -2
  253. package/src/server/plugins/engine/pageControllers/helpers/state.ts +9 -9
  254. package/src/server/plugins/engine/pageControllers/helpers/submission.ts +5 -5
  255. package/src/server/plugins/engine/pageControllers/index.ts +7 -7
  256. package/src/server/plugins/engine/pageControllers/validationOptions.ts +1 -1
  257. package/src/server/plugins/engine/plugin.ts +14 -14
  258. package/src/server/plugins/engine/routes/file-upload.ts +2 -2
  259. package/src/server/plugins/engine/routes/index.ts +10 -10
  260. package/src/server/plugins/engine/routes/payment-helper.js +4 -4
  261. package/src/server/plugins/engine/routes/payment.js +9 -9
  262. package/src/server/plugins/engine/routes/questions.ts +10 -10
  263. package/src/server/plugins/engine/routes/repeaters/item-delete.ts +6 -6
  264. package/src/server/plugins/engine/routes/repeaters/summary.ts +5 -5
  265. package/src/server/plugins/engine/services/formSubmissionService.js +2 -2
  266. package/src/server/plugins/engine/services/index.js +3 -3
  267. package/src/server/plugins/engine/services/localFormsService.js +2 -2
  268. package/src/server/plugins/engine/services/notifyService.ts +9 -9
  269. package/src/server/plugins/engine/services/uploadService.js +3 -3
  270. package/src/server/plugins/engine/types/index.ts +10 -10
  271. package/src/server/plugins/engine/types/schema.ts +2 -2
  272. package/src/server/plugins/engine/types.ts +22 -17
  273. package/src/server/plugins/engine/validationHelpers.ts +3 -3
  274. package/src/server/plugins/engine/vision.ts +3 -3
  275. package/src/server/plugins/map/index.js +2 -2
  276. package/src/server/plugins/map/routes/get-os-token.js +15 -3
  277. package/src/server/plugins/map/routes/index.js +7 -5
  278. package/src/server/plugins/map/routes/vts/esri-aerial.json +23 -0
  279. package/src/server/plugins/map/service.js +7 -4
  280. package/src/server/plugins/map/test/__stubs__/find.js +1 -1
  281. package/src/server/plugins/nunjucks/context.js +5 -5
  282. package/src/server/plugins/nunjucks/environment.js +6 -6
  283. package/src/server/plugins/nunjucks/filters/answer.js +3 -3
  284. package/src/server/plugins/nunjucks/filters/evaluate.js +2 -2
  285. package/src/server/plugins/nunjucks/filters/field.js +1 -1
  286. package/src/server/plugins/nunjucks/filters/href.js +2 -2
  287. package/src/server/plugins/nunjucks/filters/index.js +8 -8
  288. package/src/server/plugins/nunjucks/filters/page.js +1 -1
  289. package/src/server/plugins/nunjucks/index.js +3 -3
  290. package/src/server/plugins/nunjucks/plugin.js +3 -3
  291. package/src/server/plugins/nunjucks/render.js +2 -2
  292. package/src/server/plugins/nunjucks/types.js +1 -1
  293. package/src/server/plugins/payment/helper.js +2 -2
  294. package/src/server/plugins/payment/service.js +4 -4
  295. package/src/server/plugins/postcode-lookup/index.js +2 -2
  296. package/src/server/plugins/postcode-lookup/models/index.js +3 -3
  297. package/src/server/plugins/postcode-lookup/routes/index.js +24 -14
  298. package/src/server/plugins/postcode-lookup/service.js +7 -4
  299. package/src/server/plugins/postcode-lookup/types.js +1 -1
  300. package/src/server/plugins/session.ts +1 -1
  301. package/src/server/routes/index.ts +2 -2
  302. package/src/server/routes/public.ts +1 -1
  303. package/src/server/routes/types.ts +1 -1
  304. package/src/server/schemas/index.ts +2 -2
  305. package/src/server/secure-context.js +1 -1
  306. package/src/server/services/cacheService.ts +13 -18
  307. package/src/server/services/httpService.ts +1 -1
  308. package/src/server/services/index.ts +1 -1
  309. package/src/server/types.ts +7 -7
  310. package/src/server/utils/notify.ts +2 -2
  311. package/src/server/utils/utils.js +1 -1
  312. package/src/typings/hapi/index.d.ts +4 -4
  313. package/src/typings/joi/index.d.ts +1 -1
  314. package/src/server/common/helpers/logging/logger-options.test.ts +0 -50
  315. package/src/server/index.test.ts +0 -644
  316. package/src/server/plugins/engine/beta/form-context.test.ts +0 -373
  317. package/src/server/plugins/engine/components/AutocompleteField.test.ts +0 -362
  318. package/src/server/plugins/engine/components/CheckboxesField.test.ts +0 -486
  319. package/src/server/plugins/engine/components/DatePartsField.test.ts +0 -927
  320. package/src/server/plugins/engine/components/DeclarationField.test.ts +0 -560
  321. package/src/server/plugins/engine/components/Details.test.ts +0 -49
  322. package/src/server/plugins/engine/components/EastingNorthingField.test.ts +0 -727
  323. package/src/server/plugins/engine/components/EmailAddressField.test.ts +0 -445
  324. package/src/server/plugins/engine/components/FileUploadField.test.ts +0 -1079
  325. package/src/server/plugins/engine/components/GeospatialField.test.ts +0 -380
  326. package/src/server/plugins/engine/components/HiddenField.test.ts +0 -188
  327. package/src/server/plugins/engine/components/Html.test.ts +0 -48
  328. package/src/server/plugins/engine/components/InsetText.test.ts +0 -48
  329. package/src/server/plugins/engine/components/LatLongField.test.ts +0 -898
  330. package/src/server/plugins/engine/components/List.test.ts +0 -79
  331. package/src/server/plugins/engine/components/LocationFieldBase.test.ts +0 -253
  332. package/src/server/plugins/engine/components/LocationFieldHelpers.test.ts +0 -743
  333. package/src/server/plugins/engine/components/Markdown.test.ts +0 -48
  334. package/src/server/plugins/engine/components/MonthYearField.test.ts +0 -617
  335. package/src/server/plugins/engine/components/MultilineTextField.test.ts +0 -647
  336. package/src/server/plugins/engine/components/NationalGridFieldNumberField.test.ts +0 -449
  337. package/src/server/plugins/engine/components/NumberField.test.ts +0 -723
  338. package/src/server/plugins/engine/components/OsGridRefField.test.ts +0 -460
  339. package/src/server/plugins/engine/components/PaymentField.test.ts +0 -745
  340. package/src/server/plugins/engine/components/RadiosField.test.ts +0 -297
  341. package/src/server/plugins/engine/components/SelectField.test.ts +0 -289
  342. package/src/server/plugins/engine/components/TelephoneNumberField.test.ts +0 -384
  343. package/src/server/plugins/engine/components/TextField.test.ts +0 -521
  344. package/src/server/plugins/engine/components/UkAddressField.test.ts +0 -806
  345. package/src/server/plugins/engine/components/YesNoField.test.ts +0 -256
  346. package/src/server/plugins/engine/components/helpers/components.test.ts +0 -399
  347. package/src/server/plugins/engine/components/helpers/geospatial.test.js +0 -55
  348. package/src/server/plugins/engine/components/helpers/helpers.test.ts +0 -219
  349. package/src/server/plugins/engine/date-helper.test.ts +0 -47
  350. package/src/server/plugins/engine/helpers.test.ts +0 -868
  351. package/src/server/plugins/engine/models/FormModel.test.ts +0 -725
  352. package/src/server/plugins/engine/models/SummaryViewModel.test.ts +0 -472
  353. package/src/server/plugins/engine/options.test.js +0 -63
  354. package/src/server/plugins/engine/outputFormatters/adapter/v1.location.test.ts +0 -356
  355. package/src/server/plugins/engine/outputFormatters/adapter/v1.test.ts +0 -871
  356. package/src/server/plugins/engine/outputFormatters/human/v1.payment.test.ts +0 -147
  357. package/src/server/plugins/engine/outputFormatters/human/v1.test.ts +0 -145
  358. package/src/server/plugins/engine/outputFormatters/index.test.ts +0 -17
  359. package/src/server/plugins/engine/outputFormatters/machine/v1.test.ts +0 -268
  360. package/src/server/plugins/engine/outputFormatters/machine/v2.location.test.ts +0 -341
  361. package/src/server/plugins/engine/outputFormatters/machine/v2.payment.test.ts +0 -115
  362. package/src/server/plugins/engine/outputFormatters/machine/v2.test.ts +0 -311
  363. package/src/server/plugins/engine/pageControllers/FileUploadPageController.test.ts +0 -1372
  364. package/src/server/plugins/engine/pageControllers/PageController.test.ts +0 -246
  365. package/src/server/plugins/engine/pageControllers/QuestionPageController.test.ts +0 -1686
  366. package/src/server/plugins/engine/pageControllers/RepeatPageController.test.ts +0 -279
  367. package/src/server/plugins/engine/pageControllers/StartPageController.test.ts +0 -32
  368. package/src/server/plugins/engine/pageControllers/StatusPageController.test.ts +0 -32
  369. package/src/server/plugins/engine/pageControllers/SummaryPageController.test.ts +0 -89
  370. package/src/server/plugins/engine/pageControllers/TerminalController.test.ts +0 -37
  371. package/src/server/plugins/engine/pageControllers/errors.test.ts +0 -78
  372. package/src/server/plugins/engine/pageControllers/helpers/helpers.test.ts +0 -182
  373. package/src/server/plugins/engine/pageControllers/helpers/state.test.ts +0 -359
  374. package/src/server/plugins/engine/pageControllers/helpers/submission.test.ts +0 -373
  375. package/src/server/plugins/engine/referenceNumbers.test.ts +0 -74
  376. package/src/server/plugins/engine/routes/index.test.ts +0 -332
  377. package/src/server/plugins/engine/routes/payment-helper.test.js +0 -136
  378. package/src/server/plugins/engine/routes/payment.test.js +0 -180
  379. package/src/server/plugins/engine/routes/questions.test.ts +0 -502
  380. package/src/server/plugins/engine/routes/repeaters/item-delete.test.ts +0 -83
  381. package/src/server/plugins/engine/routes/repeaters/summary.test.ts +0 -75
  382. package/src/server/plugins/engine/services/formsService.test.js +0 -26
  383. package/src/server/plugins/engine/services/notifyService.test.ts +0 -310
  384. package/src/server/plugins/engine/types/schema.test.ts +0 -234
  385. package/src/server/plugins/engine/views/components/service-banner/template.test.js +0 -43
  386. package/src/server/plugins/engine/views/components/tag-env/template.test.js +0 -28
  387. package/src/server/plugins/engine/views/partials/preview-banner.test.js +0 -122
  388. package/src/server/plugins/map/routes/get-os-token.test.js +0 -55
  389. package/src/server/plugins/map/service.test.js +0 -144
  390. package/src/server/plugins/nunjucks/context.test.js +0 -109
  391. package/src/server/plugins/nunjucks/enviroment.test.js +0 -207
  392. package/src/server/plugins/nunjucks/filters/answer.test.js +0 -92
  393. package/src/server/plugins/nunjucks/filters/field.test.js +0 -75
  394. package/src/server/plugins/nunjucks/filters/href.test.js +0 -80
  395. package/src/server/plugins/nunjucks/filters/merge.test.js +0 -15
  396. package/src/server/plugins/nunjucks/filters/page.test.js +0 -65
  397. package/src/server/plugins/payment/helper.test.js +0 -29
  398. package/src/server/plugins/payment/service.test.js +0 -218
  399. package/src/server/plugins/postcode-lookup/service.test.js +0 -177
  400. package/src/server/postcode-lookup.test.ts +0 -64
  401. package/src/server/routes/dummy-api.test.ts +0 -97
  402. package/src/server/services/cacheService.test.ts +0 -308
  403. package/src/server/services/httpService.test.js +0 -491
  404. package/src/server/utils/file-form-service.test.js +0 -127
  405. package/src/server/utils/notify.test.ts +0 -37
  406. package/src/server/utils/secure-context/get-trust-store-certs.test.js +0 -19
  407. package/src/server/utils/utils.test.js +0 -69
@@ -1,1372 +0,0 @@
1
- /* eslint-disable @typescript-eslint/dot-notation */
2
- import { ComponentType, type ComponentDef } from '@defra/forms-model'
3
- import Boom from '@hapi/boom'
4
- import { type ValidationErrorItem, type ValidationResult } from 'joi'
5
-
6
- import {
7
- FileUploadField,
8
- tempItemSchema
9
- } from '~/src/server/plugins/engine/components/FileUploadField.js'
10
- import { TextField } from '~/src/server/plugins/engine/components/TextField.js'
11
- import {
12
- getCacheService,
13
- getError
14
- } from '~/src/server/plugins/engine/helpers.js'
15
- import { FormModel } from '~/src/server/plugins/engine/models/FormModel.js'
16
- import {
17
- FileUploadPageController,
18
- prepareStatus
19
- } from '~/src/server/plugins/engine/pageControllers/FileUploadPageController.js'
20
- import { QuestionPageController } from '~/src/server/plugins/engine/pageControllers/QuestionPageController.js'
21
- import { serverWithSaveAndExit } from '~/src/server/plugins/engine/pageControllers/__stubs__/server.js'
22
- import * as pageHelpers from '~/src/server/plugins/engine/pageControllers/helpers/index.js'
23
- import { getFormMetadata } from '~/src/server/plugins/engine/services/formsService.js'
24
- import * as uploadService from '~/src/server/plugins/engine/services/uploadService.js'
25
- import {
26
- FileStatus,
27
- UploadStatus,
28
- type FeaturedFormPageViewModel,
29
- type FormContext,
30
- type FormContextRequest,
31
- type FormPayloadParams,
32
- type FormSubmissionState,
33
- type UploadStatusFileResponse,
34
- type UploadStatusResponse
35
- } from '~/src/server/plugins/engine/types.js'
36
- import {
37
- type FormRequest,
38
- type FormRequestPayload,
39
- type FormResponseToolkit
40
- } from '~/src/server/routes/types.js'
41
- import { type CacheService } from '~/src/server/services/index.js'
42
- import * as fixtures from '~/test/fixtures/index.js'
43
- import definition from '~/test/form/definitions/file-upload-basic.js'
44
-
45
- jest.mock('~/src/server/plugins/engine/services/formsService.js')
46
-
47
- type TestableFileUploadPageController = FileUploadPageController & {
48
- initiateAndStoreNewUpload(
49
- req: FormRequest,
50
- state: FormSubmissionState
51
- ): Promise<FormSubmissionState>
52
- mergeState(
53
- req: FormRequest,
54
- state: FormSubmissionState,
55
- merge: object
56
- ): Promise<FormSubmissionState>
57
- checkUploadStatus(
58
- request: FormRequest,
59
- state: FormSubmissionState,
60
- depth?: number
61
- ): Promise<FormSubmissionState>
62
- prepareStatus(status: UploadStatusFileResponse): UploadStatusFileResponse
63
- }
64
-
65
- describe('FileUploadPageController', () => {
66
- let model: FormModel
67
- let controller: FileUploadPageController
68
- let request: FormRequest
69
-
70
- beforeEach(() => {
71
- const { pages } = structuredClone(definition)
72
-
73
- model = new FormModel(definition, {
74
- basePath: 'test'
75
- })
76
-
77
- jest.mocked(getFormMetadata).mockResolvedValue(fixtures.form.metadata)
78
-
79
- controller = new FileUploadPageController(model, pages[0])
80
- request = {
81
- params: {
82
- slug: 'test-form'
83
- },
84
- logger: {
85
- info: jest.fn(),
86
- error: jest.fn(),
87
- fatal: jest.fn(),
88
- warn: jest.fn(),
89
- debug: jest.fn(),
90
- trace: jest.fn(),
91
- level: 'info'
92
- },
93
- server: {
94
- plugins: {
95
- 'forms-engine-plugin': {
96
- baseLayoutPath: '',
97
- cacheService: {
98
- setFlash: jest.fn(),
99
- setState: jest
100
- .fn()
101
- .mockImplementation((req, updated) => Promise.resolve(updated))
102
- } as unknown as CacheService
103
- }
104
- }
105
- },
106
- query: {}
107
- } as unknown as FormRequest
108
- })
109
-
110
- afterEach(() => {
111
- jest.restoreAllMocks()
112
- jest.clearAllMocks()
113
- })
114
-
115
- describe('Constructor', () => {
116
- const textComponent: ComponentDef = {
117
- name: 'fullName',
118
- title: 'Full name',
119
- type: ComponentType.TextField,
120
- options: {},
121
- schema: {}
122
- }
123
-
124
- it('throws unless there is exactly 1 file upload component', () => {
125
- const { pages } = structuredClone(definition)
126
-
127
- // @ts-expect-error - Allow invalid component for test
128
- pages[0].components = [textComponent]
129
-
130
- expect(() => new FileUploadPageController(model, pages[0])).toThrow(
131
- `Expected 1 FileUploadFieldComponent in FileUploadPageController '${pages[0].path}'`
132
- )
133
- })
134
-
135
- it('throws unless file upload component is the first in the form', () => {
136
- const { pages } = structuredClone(definition)
137
-
138
- // @ts-expect-error - Allow invalid component for test
139
- pages[0].components.unshift(textComponent)
140
-
141
- expect(() => new FileUploadPageController(model, pages[0])).toThrow(
142
- `Expected 'fileUpload' to be the first form component in FileUploadPageController '${pages[0].path}'`
143
- )
144
- })
145
- })
146
-
147
- describe('Form validation', () => {
148
- it('includes title text and error', () => {
149
- const result = controller.collection.validate()
150
-
151
- expect(result.errors).toEqual([
152
- {
153
- path: ['fileUpload'],
154
- href: '#fileUpload',
155
- name: 'fileUpload',
156
- text: 'Select upload something',
157
- context: {
158
- key: 'fileUpload',
159
- label: 'Upload something',
160
- title: 'Upload something'
161
- }
162
- }
163
- ])
164
- })
165
-
166
- it('includes all field errors', () => {
167
- const result = controller.collection.validate()
168
- expect(result.errors).toHaveLength(1)
169
- })
170
- })
171
-
172
- describe('checkUploadStatus', () => {
173
- describe('error handling', () => {
174
- it('throws error when getUploadStatus returns empty response', async () => {
175
- const state = {
176
- upload: {
177
- [controller.path]: {
178
- upload: {
179
- uploadId: 'some-id',
180
- uploadUrl: 'some-url',
181
- statusUrl: 'some-status-url'
182
- },
183
- files: []
184
- }
185
- }
186
- } as unknown as FormSubmissionState
187
-
188
- jest
189
- .spyOn(uploadService, 'getUploadStatus')
190
- .mockResolvedValue(undefined)
191
-
192
- await expect(
193
- controller['checkUploadStatus'](request, state, 1)
194
- ).rejects.toThrow(
195
- 'Unexpected empty response from getUploadStatus for some-id'
196
- )
197
- })
198
-
199
- it('initiates new upload when getUploadStatus throws a 404 error', async () => {
200
- const state = {
201
- upload: {
202
- [controller.path]: {
203
- upload: {
204
- uploadId: 'some-id',
205
- uploadUrl: 'some-url',
206
- statusUrl: 'some-status-url'
207
- },
208
- files: []
209
- }
210
- }
211
- } as unknown as FormSubmissionState
212
-
213
- const notFoundError = Boom.notFound('Upload not found')
214
-
215
- jest
216
- .spyOn(uploadService, 'getUploadStatus')
217
- .mockRejectedValue(notFoundError)
218
-
219
- const testController = controller as TestableFileUploadPageController
220
- const initiateSpy = jest.spyOn(
221
- testController,
222
- 'initiateAndStoreNewUpload'
223
- )
224
- initiateSpy.mockResolvedValue(state as never)
225
-
226
- const result = await controller['checkUploadStatus'](request, state, 1)
227
-
228
- expect(initiateSpy).toHaveBeenCalledWith(request, state)
229
- expect(result).toBe(state)
230
- })
231
-
232
- it('re-throws non-404 Boom errors from getUploadStatus', async () => {
233
- const state = {
234
- upload: {
235
- [controller.path]: {
236
- upload: {
237
- uploadId: 'some-id',
238
- uploadUrl: 'some-url',
239
- statusUrl: 'some-status-url'
240
- },
241
- files: []
242
- }
243
- }
244
- } as unknown as FormSubmissionState
245
-
246
- const serverError = Boom.internal('Server error')
247
-
248
- jest
249
- .spyOn(uploadService, 'getUploadStatus')
250
- .mockRejectedValue(serverError)
251
-
252
- await expect(
253
- controller['checkUploadStatus'](request, state, 1)
254
- ).rejects.toThrow('Server error')
255
- })
256
-
257
- it('re-throws non-Boom errors from getUploadStatus', async () => {
258
- const state = {
259
- upload: {
260
- [controller.path]: {
261
- upload: {
262
- uploadId: 'some-id',
263
- uploadUrl: 'some-url',
264
- statusUrl: 'some-status-url'
265
- },
266
- files: []
267
- }
268
- }
269
- } as unknown as FormSubmissionState
270
-
271
- const networkError = new Error('Network failure')
272
-
273
- jest
274
- .spyOn(uploadService, 'getUploadStatus')
275
- .mockRejectedValue(networkError)
276
-
277
- await expect(
278
- controller['checkUploadStatus'](request, state, 1)
279
- ).rejects.toThrow('Network failure')
280
- })
281
-
282
- it('handles pending upload with backoff and retries', async () => {
283
- const state = {
284
- upload: {
285
- [controller.path]: {
286
- upload: {
287
- uploadId: 'some-id',
288
- uploadUrl: 'some-url',
289
- statusUrl: 'some-status-url'
290
- },
291
- files: []
292
- }
293
- }
294
- } as unknown as FormSubmissionState
295
-
296
- const pendingStatus = {
297
- uploadStatus: UploadStatus.pending,
298
- form: { file: { fileStatus: FileStatus.complete } }
299
- }
300
-
301
- const getUploadStatusSpy = jest
302
- .spyOn(uploadService, 'getUploadStatus')
303
- .mockResolvedValueOnce(pendingStatus as UploadStatusResponse)
304
- .mockResolvedValueOnce({
305
- uploadStatus: UploadStatus.initiated
306
- } as UploadStatusResponse)
307
-
308
- await controller['checkUploadStatus'](request, state, 1)
309
-
310
- expect(getUploadStatusSpy).toHaveBeenCalledTimes(2)
311
- expect(request.logger.info).toHaveBeenCalled()
312
-
313
- /* eslint-disable-next-line @typescript-eslint/no-unsafe-member-access */
314
- const logMsg = (request.logger.info as jest.Mock).mock.calls[0][0]
315
- expect(logMsg).toEqual(expect.stringContaining('Waiting'))
316
- expect(logMsg).toEqual(expect.stringContaining('some-id'))
317
- }, 3000)
318
-
319
- it('throws gateway timeout when maximum retry depth is exceeded, logs an error, and re-initiates a new upload', async () => {
320
- const state = {
321
- upload: {
322
- [controller.path]: {
323
- upload: {
324
- uploadId: 'some-id',
325
- uploadUrl: 'some-url',
326
- statusUrl: 'some-status-url'
327
- },
328
- files: []
329
- }
330
- }
331
- } as unknown as FormSubmissionState
332
-
333
- const pendingStatus = {
334
- uploadStatus: UploadStatus.pending,
335
- form: { file: { fileStatus: FileStatus.pending } }
336
- }
337
-
338
- jest
339
- .spyOn(uploadService, 'getUploadStatus')
340
- .mockResolvedValue(pendingStatus as UploadStatusResponse)
341
-
342
- const initiateSpy = jest
343
- .spyOn(
344
- controller as TestableFileUploadPageController,
345
- 'initiateAndStoreNewUpload'
346
- )
347
- .mockResolvedValue(state as never)
348
-
349
- await expect(
350
- controller['checkUploadStatus'](request, state, 7)
351
- ).rejects.toThrow(
352
- 'Timed out waiting for some-id after cumulative retries exceeding 55 seconds'
353
- )
354
-
355
- expect(request.logger.error).toHaveBeenCalledWith(
356
- expect.any(Error),
357
- expect.stringContaining(
358
- '[uploadTimeout] Exceeded cumulative retry delay for uploadId: some-id at depth: 7 - re-initiating new upload'
359
- )
360
- )
361
-
362
- expect(initiateSpy).toHaveBeenCalledWith(request, state)
363
- })
364
-
365
- it('throws error when initiateUpload returns undefined', async () => {
366
- const state = {
367
- upload: {
368
- [controller.path]: {
369
- upload: {},
370
- files: []
371
- }
372
- }
373
- } as unknown as FormSubmissionState
374
-
375
- jest.spyOn(uploadService, 'initiateUpload').mockResolvedValue(undefined)
376
-
377
- await expect(
378
- controller['checkUploadStatus'](request, state, 1)
379
- ).rejects.toThrow('Unexpected empty response from initiateUpload')
380
- })
381
-
382
- it('handles pending file status with custom error message', async () => {
383
- const state = {
384
- upload: {
385
- [controller.path]: {
386
- upload: {
387
- uploadId: 'some-id',
388
- uploadUrl: 'some-url',
389
- statusUrl: 'some-status-url'
390
- },
391
- files: []
392
- }
393
- }
394
- } as unknown as FormSubmissionState
395
-
396
- const pendingStatus = {
397
- uploadStatus: UploadStatus.ready,
398
- form: {
399
- file: {
400
- fileStatus: FileStatus.pending,
401
- errorMessage: 'Custom error message'
402
- }
403
- }
404
- }
405
-
406
- jest
407
- .spyOn(uploadService, 'getUploadStatus')
408
- .mockResolvedValue(pendingStatus as UploadStatusResponse)
409
-
410
- jest.spyOn(tempItemSchema, 'validate').mockReturnValue({
411
- value: {
412
- uploadId: 'some-id',
413
- status: pendingStatus,
414
- type: 'object.unknown',
415
- path: ['fileUpload', 'errorMessage'],
416
- context: { value: 'Custom error message' }
417
- },
418
- error: undefined
419
- } as ValidationResult)
420
-
421
- const testController = controller as TestableFileUploadPageController
422
- const initiateSpy = jest.spyOn(
423
- testController,
424
- 'initiateAndStoreNewUpload'
425
- )
426
- initiateSpy.mockResolvedValue(state as never)
427
-
428
- const cacheService = getCacheService(request.server)
429
- await controller['checkUploadStatus'](request, state, 1)
430
-
431
- expect(cacheService.setFlash).toHaveBeenCalledWith(request, {
432
- errors: [
433
- {
434
- path: ['fileUpload'],
435
- href: '#fileUpload',
436
- name: 'fileUpload',
437
- text: 'Custom error message'
438
- }
439
- ]
440
- })
441
- })
442
- })
443
-
444
- describe('state management', () => {
445
- it('returns existing state when upload status is initiated', async () => {
446
- const state = {
447
- upload: {
448
- [controller.path]: {
449
- upload: {
450
- uploadId: 'some-id',
451
- uploadUrl: 'some-url',
452
- statusUrl: 'some-status-url'
453
- },
454
- files: []
455
- }
456
- }
457
- } as unknown as FormSubmissionState
458
-
459
- jest.spyOn(uploadService, 'getUploadStatus').mockResolvedValue({
460
- uploadStatus: UploadStatus.initiated
461
- } as UploadStatusResponse)
462
- const result = await controller['checkUploadStatus'](request, state, 1)
463
- expect(result).toBe(state)
464
- })
465
-
466
- it('returns early when all files are updated', async () => {
467
- const files = ['file1', 'file2']
468
- const filesUpdated = [...files]
469
- const state = {
470
- upload: {
471
- [controller.path]: {
472
- upload: {
473
- uploadId: 'some-id',
474
- uploadUrl: 'some-url',
475
- statusUrl: 'some-status-url'
476
- },
477
- files,
478
- filesUpdated
479
- }
480
- }
481
- } as unknown as FormSubmissionState
482
-
483
- const readyStatus = {
484
- uploadStatus: UploadStatus.ready,
485
- form: { file: { fileStatus: FileStatus.complete } }
486
- }
487
-
488
- jest
489
- .spyOn(uploadService, 'getUploadStatus')
490
- .mockResolvedValue(readyStatus as UploadStatusResponse)
491
-
492
- jest.spyOn(tempItemSchema, 'validate').mockReturnValue({
493
- value: { status: readyStatus },
494
- error: undefined
495
- } as ValidationResult)
496
-
497
- const testController = controller as TestableFileUploadPageController
498
- const initiateSpy = jest.spyOn(
499
- testController,
500
- 'initiateAndStoreNewUpload'
501
- ) as jest.SpyInstance<
502
- Promise<FormSubmissionState>,
503
- [FormRequest, FormSubmissionState]
504
- >
505
-
506
- initiateSpy.mockResolvedValue(state)
507
-
508
- const result = await controller['checkUploadStatus'](request, state, 1)
509
-
510
- expect(result).toBe(state)
511
- })
512
-
513
- it('initiates new upload when no upload exists', async () => {
514
- const state = {
515
- upload: {
516
- [controller.path]: {
517
- upload: {},
518
- files: []
519
- }
520
- }
521
- } as unknown as FormSubmissionState
522
-
523
- const testController = controller as TestableFileUploadPageController
524
-
525
- const initiateSpy = jest.spyOn(
526
- testController,
527
- 'initiateAndStoreNewUpload'
528
- ) as jest.SpyInstance<
529
- Promise<FormSubmissionState>,
530
- [FormRequest, FormSubmissionState]
531
- >
532
-
533
- initiateSpy.mockImplementation(
534
- (_req: FormRequest, s: FormSubmissionState) =>
535
- Promise.resolve(Object.assign({}, s, { initiated: true }))
536
- )
537
-
538
- const result = await controller['checkUploadStatus'](request, state, 1)
539
-
540
- expect(initiateSpy).toHaveBeenCalled()
541
- expect(result.initiated).toBe(true)
542
- })
543
-
544
- it('initiates new upload when file validation fails', async () => {
545
- const state = {
546
- upload: {
547
- [controller.path]: {
548
- upload: {
549
- uploadId: 'some-id',
550
- uploadUrl: 'some-url',
551
- statusUrl: 'some-status-url'
552
- },
553
- files: []
554
- }
555
- }
556
- } as unknown as FormSubmissionState
557
-
558
- jest.spyOn(uploadService, 'getUploadStatus').mockResolvedValue({
559
- uploadStatus: UploadStatus.ready,
560
- form: { file: { fileStatus: FileStatus.complete } }
561
- } as UploadStatusResponse)
562
-
563
- jest.spyOn(tempItemSchema, 'validate').mockReturnValue({
564
- value: {},
565
- error: new Error('Validation failed')
566
- } as ValidationResult)
567
-
568
- const testController = controller as TestableFileUploadPageController
569
-
570
- const initiateSpy = jest.spyOn(
571
- testController,
572
- 'initiateAndStoreNewUpload'
573
- ) as jest.SpyInstance<
574
- Promise<FormSubmissionState>,
575
- [FormRequest, FormSubmissionState]
576
- >
577
-
578
- initiateSpy.mockImplementation(
579
- (
580
- _req: FormRequest,
581
- s: FormSubmissionState
582
- ): Promise<FormSubmissionState> =>
583
- Promise.resolve(Object.assign({}, s, { newUpload: true }))
584
- )
585
- const result = await controller['checkUploadStatus'](request, state, 1)
586
-
587
- expect(initiateSpy).toHaveBeenCalled()
588
- expect(result.newUpload).toBe(true)
589
- })
590
-
591
- it('merges state when file upload is complete', async () => {
592
- const state = {
593
- upload: {
594
- [controller.path]: {
595
- upload: {
596
- uploadId: 'some-id',
597
- uploadUrl: 'some-url',
598
- statusUrl: 'some-status-url'
599
- },
600
- files: []
601
- }
602
- }
603
- } as unknown as FormSubmissionState
604
-
605
- const completeStatus = {
606
- uploadStatus: UploadStatus.ready,
607
- form: { file: { fileStatus: FileStatus.complete } }
608
- }
609
-
610
- jest
611
- .spyOn(uploadService, 'getUploadStatus')
612
- .mockResolvedValue(completeStatus as UploadStatusResponse)
613
-
614
- jest.spyOn(tempItemSchema, 'validate').mockReturnValue({
615
- value: {
616
- status: completeStatus,
617
- uploadId: 'some-id'
618
- },
619
- error: undefined
620
- } as ValidationResult)
621
-
622
- const testController = controller as TestableFileUploadPageController
623
-
624
- const mergeStateSpy = jest.spyOn(
625
- testController,
626
- 'mergeState'
627
- ) as jest.SpyInstance<
628
- Promise<FormSubmissionState>,
629
- [FormRequest, FormSubmissionState, object]
630
- >
631
-
632
- mergeStateSpy.mockImplementation(
633
- (
634
- _req: FormRequest,
635
- s: FormSubmissionState,
636
- _merge: object
637
- ): Promise<FormSubmissionState> =>
638
- Promise.resolve(Object.assign({}, s, { merged: true }))
639
- )
640
-
641
- const initiateSpy = jest.spyOn(
642
- testController,
643
- 'initiateAndStoreNewUpload'
644
- ) as jest.SpyInstance<
645
- Promise<FormSubmissionState>,
646
- [FormRequest, FormSubmissionState]
647
- >
648
-
649
- initiateSpy.mockImplementation(
650
- (
651
- _req: FormRequest,
652
- s: FormSubmissionState
653
- ): Promise<FormSubmissionState> =>
654
- Promise.resolve(Object.assign({}, s, { newUpload: true }))
655
- )
656
-
657
- const result = await controller['checkUploadStatus'](request, state, 1)
658
-
659
- expect(mergeStateSpy).toHaveBeenCalled()
660
- expect(result.newUpload).toBe(true)
661
- })
662
- })
663
-
664
- describe('error messaging', () => {
665
- describe('when file status is not complete', () => {
666
- it('sets flash error with provided message', async () => {
667
- const state = {
668
- upload: {
669
- [controller.path]: {
670
- upload: {
671
- uploadId: 'some-id',
672
- uploadUrl: 'some-url',
673
- statusUrl: 'some-status-url'
674
- },
675
- files: []
676
- }
677
- }
678
- } as unknown as FormSubmissionState
679
-
680
- const errorStatus = {
681
- uploadStatus: UploadStatus.ready,
682
- form: {
683
- file: {
684
- fileStatus: FileStatus.rejected,
685
- errorMessage: 'Test error'
686
- }
687
- }
688
- }
689
-
690
- jest
691
- .spyOn(uploadService, 'getUploadStatus')
692
- .mockResolvedValue(errorStatus as UploadStatusResponse)
693
-
694
- jest.spyOn(tempItemSchema, 'validate').mockReturnValue({
695
- value: {
696
- status: errorStatus,
697
- uploadId: 'some-id'
698
- },
699
- error: undefined
700
- } as ValidationResult)
701
-
702
- const testController = controller as TestableFileUploadPageController
703
-
704
- const initiateSpy = jest.spyOn(
705
- testController,
706
- 'initiateAndStoreNewUpload'
707
- ) as jest.SpyInstance<
708
- Promise<FormSubmissionState>,
709
- [FormRequest, FormSubmissionState]
710
- >
711
-
712
- initiateSpy.mockImplementation(
713
- (
714
- _req: FormRequest,
715
- s: FormSubmissionState
716
- ): Promise<FormSubmissionState> =>
717
- Promise.resolve(Object.assign({}, s, { newUpload: true }))
718
- )
719
-
720
- const cacheService = getCacheService(request.server)
721
-
722
- await controller['checkUploadStatus'](request, state, 1)
723
-
724
- expect(cacheService.setFlash).toHaveBeenCalledWith(request, {
725
- errors: [
726
- {
727
- path: ['fileUpload'],
728
- href: '#fileUpload',
729
- name: 'fileUpload',
730
- text: 'Test error'
731
- }
732
- ]
733
- })
734
- })
735
- })
736
-
737
- describe('when file has error status', () => {
738
- it('sets flash error with error message', async () => {
739
- const state = {
740
- upload: {
741
- [controller.path]: {
742
- upload: {
743
- uploadId: 'some-id',
744
- uploadUrl: 'some-url',
745
- statusUrl: 'some-status-url'
746
- },
747
- files: []
748
- }
749
- }
750
- } as unknown as FormSubmissionState
751
-
752
- const errorStatus = {
753
- uploadStatus: UploadStatus.ready,
754
- form: {
755
- file: {
756
- fileStatus: FileStatus.rejected,
757
- errorMessage: 'Test error message'
758
- }
759
- }
760
- }
761
-
762
- jest
763
- .spyOn(uploadService, 'getUploadStatus')
764
- .mockResolvedValue(errorStatus as UploadStatusResponse)
765
-
766
- jest.spyOn(tempItemSchema, 'validate').mockReturnValue({
767
- value: { status: errorStatus },
768
- error: undefined
769
- } as ValidationResult)
770
-
771
- const testController = controller as TestableFileUploadPageController
772
-
773
- const initiateSpy = jest.spyOn(
774
- testController,
775
- 'initiateAndStoreNewUpload'
776
- ) as jest.SpyInstance<
777
- Promise<FormSubmissionState>,
778
- [FormRequest, FormSubmissionState]
779
- >
780
-
781
- initiateSpy.mockResolvedValue(state)
782
-
783
- const cacheService = getCacheService(request.server)
784
- await controller['checkUploadStatus'](request, state, 1)
785
-
786
- expect(cacheService.setFlash).toHaveBeenCalledWith(request, {
787
- errors: [
788
- {
789
- path: ['fileUpload'],
790
- href: '#fileUpload',
791
- name: 'fileUpload',
792
- text: 'Test error message'
793
- }
794
- ]
795
- })
796
- })
797
-
798
- it('collects all file errors into a single flash when multiple files fail', async () => {
799
- const state = {
800
- upload: {
801
- [controller.path]: {
802
- upload: {
803
- uploadId: 'some-id',
804
- uploadUrl: 'some-url',
805
- statusUrl: 'some-status-url'
806
- },
807
- files: []
808
- }
809
- }
810
- } as unknown as FormSubmissionState
811
-
812
- const errorStatus = {
813
- uploadStatus: UploadStatus.ready,
814
- form: {
815
- file: [
816
- {
817
- fileStatus: FileStatus.rejected,
818
- errorMessage: 'File too large'
819
- },
820
- {
821
- fileStatus: FileStatus.rejected,
822
- errorMessage: 'Invalid file type'
823
- }
824
- ]
825
- }
826
- }
827
-
828
- jest
829
- .spyOn(uploadService, 'getUploadStatus')
830
- .mockResolvedValue(errorStatus as unknown as UploadStatusResponse)
831
-
832
- jest.spyOn(tempItemSchema, 'validate').mockReturnValue({
833
- value: {
834
- status: errorStatus,
835
- uploadId: 'some-id'
836
- },
837
- error: undefined
838
- } as ValidationResult)
839
-
840
- const testController = controller as TestableFileUploadPageController
841
-
842
- const initiateSpy = jest.spyOn(
843
- testController,
844
- 'initiateAndStoreNewUpload'
845
- ) as jest.SpyInstance<
846
- Promise<FormSubmissionState>,
847
- [FormRequest, FormSubmissionState]
848
- >
849
-
850
- initiateSpy.mockResolvedValue(state)
851
-
852
- const cacheService = getCacheService(request.server)
853
-
854
- await controller['checkUploadStatus'](request, state, 1)
855
-
856
- expect(cacheService.setFlash).toHaveBeenCalledTimes(1)
857
- expect(cacheService.setFlash).toHaveBeenCalledWith(request, {
858
- errors: [
859
- {
860
- path: ['fileUpload'],
861
- href: '#fileUpload',
862
- name: 'fileUpload',
863
- text: 'File too large'
864
- },
865
- {
866
- path: ['fileUpload'],
867
- href: '#fileUpload',
868
- name: 'fileUpload',
869
- text: 'Invalid file type'
870
- }
871
- ]
872
- })
873
- })
874
-
875
- it('sets default error message when none provided', async () => {
876
- const state = {
877
- upload: {
878
- [controller.path]: {
879
- upload: {
880
- uploadId: 'some-id',
881
- uploadUrl: 'some-url',
882
- statusUrl: 'some-status-url'
883
- },
884
- files: []
885
- }
886
- }
887
- } as unknown as FormSubmissionState
888
-
889
- const errorStatus = {
890
- uploadStatus: UploadStatus.ready,
891
- form: {
892
- file: {
893
- fileStatus: FileStatus.rejected
894
- }
895
- }
896
- }
897
-
898
- jest
899
- .spyOn(uploadService, 'getUploadStatus')
900
- .mockResolvedValue(errorStatus as UploadStatusResponse)
901
-
902
- jest.spyOn(tempItemSchema, 'validate').mockReturnValue({
903
- value: { status: errorStatus },
904
- error: undefined
905
- } as ValidationResult)
906
-
907
- const testController = controller as TestableFileUploadPageController
908
-
909
- const initiateSpy = jest.spyOn(
910
- testController,
911
- 'initiateAndStoreNewUpload'
912
- ) as jest.SpyInstance<
913
- Promise<FormSubmissionState>,
914
- [FormRequest, FormSubmissionState]
915
- >
916
-
917
- initiateSpy.mockResolvedValue(state)
918
-
919
- const cacheService = getCacheService(request.server)
920
-
921
- await controller['checkUploadStatus'](request, state, 1)
922
-
923
- expect(cacheService.setFlash).toHaveBeenCalledWith(request, {
924
- errors: [
925
- {
926
- path: ['fileUpload'],
927
- href: '#fileUpload',
928
- name: 'fileUpload',
929
- text: 'Unknown error'
930
- }
931
- ]
932
- })
933
- })
934
- })
935
- })
936
-
937
- describe('file removal', () => {
938
- it('returns early when no file is removed', async () => {
939
- const files = [
940
- {
941
- uploadId: 'upload1',
942
- status: { form: { file: { fileId: 'file1' } } }
943
- },
944
- {
945
- uploadId: 'upload2',
946
- status: { form: { file: { fileId: 'file2' } } }
947
- }
948
- ]
949
-
950
- Object.defineProperty(request, 'params', {
951
- value: { itemId: 'nonexistent-file' },
952
- writable: true,
953
- configurable: true
954
- })
955
-
956
- const state = {
957
- upload: {
958
- [controller.path]: {
959
- upload: {
960
- uploadId: 'upload-123',
961
- uploadUrl: 'some-url',
962
- statusUrl: 'some-status-url'
963
- },
964
- files
965
- }
966
- }
967
- } as unknown as FormSubmissionState
968
-
969
- const testController = controller as TestableFileUploadPageController
970
- const mergeStateSpy = jest.spyOn(testController, 'mergeState')
971
-
972
- await controller['checkRemovedFiles'](
973
- request as FormRequestPayload,
974
- state
975
- )
976
-
977
- expect(mergeStateSpy).not.toHaveBeenCalled()
978
- })
979
-
980
- it('merges state when file is removed', async () => {
981
- const files = [
982
- {
983
- uploadId: 'upload1',
984
- status: { form: { file: { fileId: 'file1' } } }
985
- },
986
- {
987
- uploadId: 'upload2',
988
- status: { form: { file: { fileId: 'file2' } } }
989
- }
990
- ]
991
-
992
- Object.defineProperty(request, 'params', {
993
- value: { itemId: 'file1' },
994
- writable: true,
995
- configurable: true
996
- })
997
-
998
- const state = {
999
- upload: {
1000
- [controller.path]: {
1001
- upload: {
1002
- uploadId: 'upload-123',
1003
- uploadUrl: 'some-url',
1004
- statusUrl: 'some-status-url'
1005
- },
1006
- files
1007
- }
1008
- }
1009
- } as unknown as FormSubmissionState
1010
-
1011
- const testController = controller as TestableFileUploadPageController
1012
- const mergeStateSpy = jest.spyOn(testController, 'mergeState')
1013
-
1014
- await controller['checkRemovedFiles'](
1015
- request as FormRequestPayload,
1016
- state
1017
- )
1018
-
1019
- expect(mergeStateSpy).toHaveBeenCalledWith(request, state, {
1020
- upload: {
1021
- [controller.path]: {
1022
- files: [
1023
- {
1024
- uploadId: 'upload2',
1025
- status: { form: { file: { fileId: 'file2' } } }
1026
- }
1027
- ],
1028
- upload: {
1029
- uploadId: 'upload-123',
1030
- uploadUrl: 'some-url',
1031
- statusUrl: 'some-status-url'
1032
- }
1033
- }
1034
- }
1035
- })
1036
- })
1037
- })
1038
- })
1039
-
1040
- describe('prepareStatus', () => {
1041
- describe('when file is pending', () => {
1042
- it('adds error message when no error message exists', () => {
1043
- const status = {
1044
- form: {
1045
- file: {
1046
- fileStatus: FileStatus.pending,
1047
- errorMessage: undefined
1048
- }
1049
- }
1050
- } as UploadStatusFileResponse
1051
-
1052
- const result = prepareStatus(status)
1053
-
1054
- expect(result.form.file.errorMessage).toBe(
1055
- 'The selected file has not fully uploaded'
1056
- )
1057
- })
1058
-
1059
- it('preserves existing error message', () => {
1060
- const existingError = 'Existing error message'
1061
- const status = {
1062
- form: {
1063
- file: {
1064
- fileStatus: FileStatus.pending,
1065
- errorMessage: existingError
1066
- }
1067
- }
1068
- } as UploadStatusFileResponse
1069
-
1070
- const result = prepareStatus(status)
1071
-
1072
- expect(result.form.file.errorMessage).toBe(existingError)
1073
- })
1074
- })
1075
-
1076
- describe('when file is not pending', () => {
1077
- it('does not add error message', () => {
1078
- const status = {
1079
- form: {
1080
- file: {
1081
- fileStatus: FileStatus.complete,
1082
- errorMessage: undefined
1083
- }
1084
- }
1085
- } as UploadStatusFileResponse
1086
-
1087
- const result = prepareStatus(status)
1088
-
1089
- expect(result.form.file.errorMessage).toBeUndefined()
1090
- })
1091
- })
1092
- })
1093
-
1094
- describe('getErrors', () => {
1095
- let controller: FileUploadPageController
1096
-
1097
- beforeEach(() => {
1098
- const { pages } = structuredClone(definition)
1099
- const model = new FormModel(definition, { basePath: 'test' })
1100
- controller = new FileUploadPageController(model, pages[0])
1101
- })
1102
-
1103
- describe('when no details provided', () => {
1104
- it('returns undefined', () => {
1105
- const errors = controller.getErrors()
1106
- expect(errors).toBeUndefined()
1107
- })
1108
- })
1109
-
1110
- describe('error handling', () => {
1111
- it('handles non-upload errors using getError helper', () => {
1112
- const errorDetail = {
1113
- message: 'some error',
1114
- path: ['otherField'],
1115
- type: 'any.required'
1116
- }
1117
- const errors = controller.getErrors([errorDetail])
1118
- expect(errors).toEqual([getError(errorDetail)])
1119
- })
1120
-
1121
- it('handles upload root errors using getError helper', () => {
1122
- const errorDetail = {
1123
- message: 'some error',
1124
- path: ['fileUpload'],
1125
- type: 'any.required'
1126
- }
1127
- const errors = controller.getErrors([errorDetail])
1128
- expect(errors).toEqual([getError(errorDetail)])
1129
- })
1130
- })
1131
-
1132
- describe('object.unknown type errors', () => {
1133
- it('pushes an error with errorMessage', () => {
1134
- const errorDetail = {
1135
- message: 'some error',
1136
- path: ['fileUpload', 'errorMessage'],
1137
- type: 'object.unknown',
1138
- context: { value: 'some error text' }
1139
- }
1140
- const errors = controller.getErrors([errorDetail])
1141
- expect(errors).toEqual([
1142
- {
1143
- path: ['fileUpload', 'errorMessage'],
1144
- href: '#fileUpload',
1145
- name: 'fileUpload',
1146
- text: 'some error text'
1147
- }
1148
- ])
1149
- })
1150
-
1151
- it('handles non-string error message values with default text', () => {
1152
- const errorDetail = {
1153
- message: 'some error',
1154
- path: ['fileUpload', 'errorMessage'],
1155
- type: 'object.unknown',
1156
- context: { value: { some: 'object' } }
1157
- }
1158
- const errors = controller.getErrors([errorDetail])
1159
- expect(errors).toEqual([
1160
- {
1161
- path: ['fileUpload', 'errorMessage'],
1162
- href: '#fileUpload',
1163
- name: 'fileUpload',
1164
- text: 'Unknown error'
1165
- }
1166
- ])
1167
- })
1168
-
1169
- it('handles object.unknown error type with errorMessage path', () => {
1170
- const details = [
1171
- {
1172
- type: 'object.unknown',
1173
- path: ['fileUpload', 'errorMessage'],
1174
- context: { value: 'Custom error message' }
1175
- }
1176
- ] as ValidationErrorItem[]
1177
-
1178
- const errors = controller.getErrors(details)
1179
-
1180
- expect(errors).toEqual([
1181
- {
1182
- path: ['fileUpload', 'errorMessage'],
1183
- href: '#fileUpload',
1184
- name: 'fileUpload',
1185
- text: 'Custom error message'
1186
- }
1187
- ])
1188
- })
1189
- })
1190
- })
1191
-
1192
- describe('initiateAndStoreNewUpload', () => {
1193
- it('throws error when initiateUpload returns undefined', async () => {
1194
- const state = {
1195
- upload: {
1196
- '/test/file-upload': {
1197
- upload: {},
1198
- files: []
1199
- }
1200
- }
1201
- } as unknown as FormSubmissionState
1202
-
1203
- jest.spyOn(uploadService, 'initiateUpload').mockResolvedValue(undefined)
1204
-
1205
- await expect(
1206
- (
1207
- controller['initiateAndStoreNewUpload'] as (
1208
- req: FormRequest,
1209
- state: FormSubmissionState
1210
- ) => Promise<FormSubmissionState>
1211
- )(request, state)
1212
- ).rejects.toThrow('Unexpected empty response from initiateUpload')
1213
- })
1214
- })
1215
-
1216
- describe('makeGetItemDeleteRouteHandler', () => {
1217
- it('throws notFound error when file to delete does not exist', () => {
1218
- const state = {
1219
- upload: {
1220
- [controller.path]: {
1221
- files: [
1222
- {
1223
- uploadId: 'file-1',
1224
- status: {
1225
- form: { file: { fileId: 'file-1', filename: 'file-1.pdf' } }
1226
- }
1227
- },
1228
- {
1229
- uploadId: 'file-2',
1230
- status: {
1231
- form: { file: { fileId: 'file-2', filename: 'file-2.pdf' } }
1232
- }
1233
- }
1234
- ]
1235
- }
1236
- }
1237
- }
1238
-
1239
- const request = {
1240
- params: { itemId: 'I do not exist' }
1241
- } as unknown as FormRequest
1242
-
1243
- const context = { state } as unknown as FormContext
1244
- const h = {} as unknown as FormResponseToolkit
1245
-
1246
- const handler = controller.makeGetItemDeleteRouteHandler()
1247
-
1248
- expect(() => handler(request, context, h)).toThrow(
1249
- 'File to delete not found'
1250
- )
1251
- })
1252
- })
1253
-
1254
- describe('makePostItemDeleteRouteHandler', () => {
1255
- it('proceeds without deleting when confirm is false', async () => {
1256
- const request = {
1257
- params: { itemId: 'file-1' }
1258
- } as unknown as FormRequestPayload
1259
-
1260
- const h = {
1261
- redirect: jest.fn()
1262
- } as unknown as FormResponseToolkit
1263
-
1264
- const context = {
1265
- state: {}
1266
- } as unknown as FormContext
1267
-
1268
- jest
1269
- .spyOn(controller, 'getFormParams')
1270
- .mockReturnValue({ confirm: false } as unknown as FormPayloadParams)
1271
-
1272
- const proceedSpy = jest
1273
- .spyOn(controller, 'proceed')
1274
- .mockResolvedValue({ statusCode: 302 } as never)
1275
-
1276
- const handler = controller.makePostItemDeleteRouteHandler()
1277
- await handler(request, context, h)
1278
-
1279
- expect(proceedSpy).toHaveBeenCalledWith(request, h)
1280
- })
1281
- })
1282
-
1283
- describe('getViewModel', () => {
1284
- it('includes uploadId and proxyUrl in the view model', () => {
1285
- const state = {
1286
- upload: {
1287
- [controller.path]: {
1288
- upload: {
1289
- uploadId: 'some-upload-id',
1290
- uploadUrl: 'https://cdp-upload-and-scan.com/upload',
1291
- statusUrl: 'https://cdp-upload-and-scan.com/status'
1292
- },
1293
- files: []
1294
- }
1295
- }
1296
- } as unknown as FormSubmissionState
1297
-
1298
- const context = { state } as FormContext
1299
-
1300
- jest
1301
- .spyOn(QuestionPageController.prototype, 'getViewModel')
1302
- .mockReturnValue({
1303
- components: [{ model: { id: 'fileUpload' } }]
1304
- } as unknown as FeaturedFormPageViewModel)
1305
-
1306
- jest
1307
- .spyOn(pageHelpers, 'getProxyUrlForLocalDevelopment')
1308
- .mockReturnValue('http://uploader.127.0.0.1.sslip.io:7300')
1309
-
1310
- const viewModel = controller.getViewModel(
1311
- request as FormContextRequest,
1312
- context
1313
- )
1314
-
1315
- expect(viewModel.uploadId).toBe('some-upload-id')
1316
- expect(viewModel.proxyUrl).toBe('http://uploader.127.0.0.1.sslip.io:7300')
1317
- expect(viewModel.formAction).toBe(
1318
- 'https://cdp-upload-and-scan.com/upload'
1319
- )
1320
- })
1321
- })
1322
-
1323
- describe('shouldShowSaveAndExit', () => {
1324
- it('should return true when save and exit is enabled', () => {
1325
- expect(controller.shouldShowSaveAndExit(serverWithSaveAndExit)).toBe(true)
1326
- })
1327
- })
1328
-
1329
- describe('getStateKeys', () => {
1330
- it('should return nested upload path for FileUploadField component', () => {
1331
- const component = controller.fileUpload
1332
- const stateKeys = controller.getStateKeys(component)
1333
-
1334
- expect(stateKeys).toEqual(["upload['/file-upload-component']"])
1335
- })
1336
-
1337
- it('should return empty array for non-FileUploadField components', () => {
1338
- const component = new TextField(
1339
- {
1340
- name: 'testField',
1341
- title: 'Test field',
1342
- type: ComponentType.TextField,
1343
- options: {},
1344
- schema: {}
1345
- },
1346
- { model, page: controller }
1347
- )
1348
-
1349
- const stateKeys = controller.getStateKeys(component)
1350
- expect(stateKeys).toEqual([])
1351
- })
1352
-
1353
- it('should return fallback upload key when component has no page', () => {
1354
- const componentDef: ComponentDef = {
1355
- name: 'fileUpload',
1356
- title: 'Upload something',
1357
- type: ComponentType.FileUploadField,
1358
- options: {},
1359
- schema: {}
1360
- }
1361
-
1362
- // Create a component without a page reference - should return ['upload']
1363
- const component = new FileUploadField(componentDef, {
1364
- model,
1365
- page: undefined
1366
- })
1367
-
1368
- const stateKeys = controller.getStateKeys(component)
1369
- expect(stateKeys).toEqual(['upload'])
1370
- })
1371
- })
1372
- })