@cratis/scene.components 4.2.0 → 4.3.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 (248) hide show
  1. package/bindings/resolveElementBinding.ts +17 -1
  2. package/cratisComponentsDescriptors.ts +48 -0
  3. package/cratisComponentsPackage.ts +2 -0
  4. package/dist/cjs/bindings/resolveElementBinding.js +13 -1
  5. package/dist/cjs/bindings/resolveElementBinding.js.map +1 -1
  6. package/dist/cjs/cratisComponentsDescriptors.js +83 -0
  7. package/dist/cjs/cratisComponentsDescriptors.js.map +1 -0
  8. package/dist/cjs/cratisComponentsPackage.js +3 -1
  9. package/dist/cjs/cratisComponentsPackage.js.map +1 -1
  10. package/dist/cjs/index.js +2 -0
  11. package/dist/cjs/index.js.map +1 -1
  12. package/dist/esm/bindings/resolveElementBinding.d.ts.map +1 -1
  13. package/dist/esm/bindings/resolveElementBinding.js +13 -1
  14. package/dist/esm/bindings/resolveElementBinding.js.map +1 -1
  15. package/dist/esm/cratisComponentsDescriptors.d.ts +3 -0
  16. package/dist/esm/cratisComponentsDescriptors.d.ts.map +1 -0
  17. package/dist/esm/cratisComponentsDescriptors.js +81 -0
  18. package/dist/esm/cratisComponentsDescriptors.js.map +1 -0
  19. package/dist/esm/cratisComponentsPackage.d.ts.map +1 -1
  20. package/dist/esm/cratisComponentsPackage.js +3 -1
  21. package/dist/esm/cratisComponentsPackage.js.map +1 -1
  22. package/dist/esm/index.d.ts +1 -0
  23. package/dist/esm/index.d.ts.map +1 -1
  24. package/dist/esm/index.js +1 -0
  25. package/dist/esm/index.js.map +1 -1
  26. package/dist/esm/tsconfig.tsbuildinfo +1 -1
  27. package/index.ts +1 -0
  28. package/package.json +17 -16
  29. package/bindings/for_bindingRegistry/when_a_command_is_registered.ts +0 -30
  30. package/bindings/for_bindingRegistry/when_a_query_is_not_registered.ts +0 -17
  31. package/bindings/for_bindingRegistry/when_a_query_is_registered.ts +0 -30
  32. package/bindings/for_bindingRegistry/when_bindings_are_cleared.ts +0 -29
  33. package/bindings/for_bindingRegistry/when_registering_query_identities.ts +0 -81
  34. package/bindings/for_requireArcProxy/NativeProxies.ts +0 -28
  35. package/bindings/for_requireArcProxy/when_mounting_bound_adapters.tsx +0 -73
  36. package/bindings/for_requireArcProxy/when_previewing_without_arc.tsx +0 -37
  37. package/bindings/for_requireArcProxy/when_validating_a_proxy.ts +0 -44
  38. package/bindings/for_resolveElementBinding/when_resolving_a_command_binding.ts +0 -34
  39. package/bindings/for_resolveElementBinding/when_resolving_a_query_binding.ts +0 -45
  40. package/data/for_SceneDataTable/when_forwarding_query_arguments.tsx +0 -123
  41. package/data/for_SceneDataTable/when_the_query_binding_is_missing.tsx +0 -48
  42. package/data/for_SceneSingleResult/when_executing_a_native_query.tsx +0 -290
  43. package/data/for_SceneSingleResult/when_gating_the_lazy_runtime.tsx +0 -60
  44. package/dist/esm/bindings/for_bindingRegistry/when_a_command_is_registered.d.ts +0 -2
  45. package/dist/esm/bindings/for_bindingRegistry/when_a_command_is_registered.d.ts.map +0 -1
  46. package/dist/esm/bindings/for_bindingRegistry/when_a_command_is_registered.js +0 -25
  47. package/dist/esm/bindings/for_bindingRegistry/when_a_command_is_registered.js.map +0 -1
  48. package/dist/esm/bindings/for_bindingRegistry/when_a_query_is_not_registered.d.ts +0 -2
  49. package/dist/esm/bindings/for_bindingRegistry/when_a_query_is_not_registered.d.ts.map +0 -1
  50. package/dist/esm/bindings/for_bindingRegistry/when_a_query_is_not_registered.js +0 -12
  51. package/dist/esm/bindings/for_bindingRegistry/when_a_query_is_not_registered.js.map +0 -1
  52. package/dist/esm/bindings/for_bindingRegistry/when_a_query_is_registered.d.ts +0 -2
  53. package/dist/esm/bindings/for_bindingRegistry/when_a_query_is_registered.d.ts.map +0 -1
  54. package/dist/esm/bindings/for_bindingRegistry/when_a_query_is_registered.js +0 -23
  55. package/dist/esm/bindings/for_bindingRegistry/when_a_query_is_registered.js.map +0 -1
  56. package/dist/esm/bindings/for_bindingRegistry/when_bindings_are_cleared.d.ts +0 -2
  57. package/dist/esm/bindings/for_bindingRegistry/when_bindings_are_cleared.d.ts.map +0 -1
  58. package/dist/esm/bindings/for_bindingRegistry/when_bindings_are_cleared.js +0 -18
  59. package/dist/esm/bindings/for_bindingRegistry/when_bindings_are_cleared.js.map +0 -1
  60. package/dist/esm/bindings/for_bindingRegistry/when_registering_query_identities.d.ts +0 -2
  61. package/dist/esm/bindings/for_bindingRegistry/when_registering_query_identities.d.ts.map +0 -1
  62. package/dist/esm/bindings/for_bindingRegistry/when_registering_query_identities.js +0 -73
  63. package/dist/esm/bindings/for_bindingRegistry/when_registering_query_identities.js.map +0 -1
  64. package/dist/esm/bindings/for_requireArcProxy/NativeProxies.d.ts +0 -25
  65. package/dist/esm/bindings/for_requireArcProxy/NativeProxies.d.ts.map +0 -1
  66. package/dist/esm/bindings/for_requireArcProxy/NativeProxies.js +0 -23
  67. package/dist/esm/bindings/for_requireArcProxy/NativeProxies.js.map +0 -1
  68. package/dist/esm/bindings/for_requireArcProxy/when_mounting_bound_adapters.d.ts +0 -2
  69. package/dist/esm/bindings/for_requireArcProxy/when_mounting_bound_adapters.d.ts.map +0 -1
  70. package/dist/esm/bindings/for_requireArcProxy/when_mounting_bound_adapters.js +0 -56
  71. package/dist/esm/bindings/for_requireArcProxy/when_mounting_bound_adapters.js.map +0 -1
  72. package/dist/esm/bindings/for_requireArcProxy/when_previewing_without_arc.d.ts +0 -2
  73. package/dist/esm/bindings/for_requireArcProxy/when_previewing_without_arc.d.ts.map +0 -1
  74. package/dist/esm/bindings/for_requireArcProxy/when_previewing_without_arc.js +0 -32
  75. package/dist/esm/bindings/for_requireArcProxy/when_previewing_without_arc.js.map +0 -1
  76. package/dist/esm/bindings/for_requireArcProxy/when_validating_a_proxy.d.ts +0 -2
  77. package/dist/esm/bindings/for_requireArcProxy/when_validating_a_proxy.d.ts.map +0 -1
  78. package/dist/esm/bindings/for_requireArcProxy/when_validating_a_proxy.js +0 -45
  79. package/dist/esm/bindings/for_requireArcProxy/when_validating_a_proxy.js.map +0 -1
  80. package/dist/esm/bindings/for_resolveElementBinding/when_resolving_a_command_binding.d.ts +0 -2
  81. package/dist/esm/bindings/for_resolveElementBinding/when_resolving_a_command_binding.d.ts.map +0 -1
  82. package/dist/esm/bindings/for_resolveElementBinding/when_resolving_a_command_binding.js +0 -25
  83. package/dist/esm/bindings/for_resolveElementBinding/when_resolving_a_command_binding.js.map +0 -1
  84. package/dist/esm/bindings/for_resolveElementBinding/when_resolving_a_query_binding.d.ts +0 -2
  85. package/dist/esm/bindings/for_resolveElementBinding/when_resolving_a_query_binding.d.ts.map +0 -1
  86. package/dist/esm/bindings/for_resolveElementBinding/when_resolving_a_query_binding.js +0 -33
  87. package/dist/esm/bindings/for_resolveElementBinding/when_resolving_a_query_binding.js.map +0 -1
  88. package/dist/esm/data/for_SceneDataTable/when_forwarding_query_arguments.d.ts +0 -2
  89. package/dist/esm/data/for_SceneDataTable/when_forwarding_query_arguments.d.ts.map +0 -1
  90. package/dist/esm/data/for_SceneDataTable/when_forwarding_query_arguments.js +0 -107
  91. package/dist/esm/data/for_SceneDataTable/when_forwarding_query_arguments.js.map +0 -1
  92. package/dist/esm/data/for_SceneDataTable/when_the_query_binding_is_missing.d.ts +0 -2
  93. package/dist/esm/data/for_SceneDataTable/when_the_query_binding_is_missing.d.ts.map +0 -1
  94. package/dist/esm/data/for_SceneDataTable/when_the_query_binding_is_missing.js +0 -36
  95. package/dist/esm/data/for_SceneDataTable/when_the_query_binding_is_missing.js.map +0 -1
  96. package/dist/esm/data/for_SceneSingleResult/when_executing_a_native_query.d.ts +0 -2
  97. package/dist/esm/data/for_SceneSingleResult/when_executing_a_native_query.d.ts.map +0 -1
  98. package/dist/esm/data/for_SceneSingleResult/when_executing_a_native_query.js +0 -255
  99. package/dist/esm/data/for_SceneSingleResult/when_executing_a_native_query.js.map +0 -1
  100. package/dist/esm/data/for_SceneSingleResult/when_gating_the_lazy_runtime.d.ts +0 -2
  101. package/dist/esm/data/for_SceneSingleResult/when_gating_the_lazy_runtime.d.ts.map +0 -1
  102. package/dist/esm/data/for_SceneSingleResult/when_gating_the_lazy_runtime.js +0 -54
  103. package/dist/esm/data/for_SceneSingleResult/when_gating_the_lazy_runtime.js.map +0 -1
  104. package/dist/esm/editors/for_SceneObjectNavigationalBar/when_navigating_back_up_the_trail.d.ts +0 -2
  105. package/dist/esm/editors/for_SceneObjectNavigationalBar/when_navigating_back_up_the_trail.d.ts.map +0 -1
  106. package/dist/esm/editors/for_SceneObjectNavigationalBar/when_navigating_back_up_the_trail.js +0 -15
  107. package/dist/esm/editors/for_SceneObjectNavigationalBar/when_navigating_back_up_the_trail.js.map +0 -1
  108. package/dist/esm/editors/for_filterDefinitions/when_reading_filter_definitions.d.ts +0 -2
  109. package/dist/esm/editors/for_filterDefinitions/when_reading_filter_definitions.d.ts.map +0 -1
  110. package/dist/esm/editors/for_filterDefinitions/when_reading_filter_definitions.js +0 -39
  111. package/dist/esm/editors/for_filterDefinitions/when_reading_filter_definitions.js.map +0 -1
  112. package/dist/esm/editors/for_timeMachineVersions/when_reading_versions.d.ts +0 -2
  113. package/dist/esm/editors/for_timeMachineVersions/when_reading_versions.d.ts.map +0 -1
  114. package/dist/esm/editors/for_timeMachineVersions/when_reading_versions.js +0 -32
  115. package/dist/esm/editors/for_timeMachineVersions/when_reading_versions.js.map +0 -1
  116. package/dist/esm/for_cratisComponents/when_rendering_a_screen_through_the_real_renderer.d.ts +0 -2
  117. package/dist/esm/for_cratisComponents/when_rendering_a_screen_through_the_real_renderer.d.ts.map +0 -1
  118. package/dist/esm/for_cratisComponents/when_rendering_a_screen_through_the_real_renderer.js +0 -25
  119. package/dist/esm/for_cratisComponents/when_rendering_a_screen_through_the_real_renderer.js.map +0 -1
  120. package/dist/esm/for_cratisComponentsPackage/when_a_profile_ranks_it_above_the_packages_it_layers_on.d.ts +0 -2
  121. package/dist/esm/for_cratisComponentsPackage/when_a_profile_ranks_it_above_the_packages_it_layers_on.d.ts.map +0 -1
  122. package/dist/esm/for_cratisComponentsPackage/when_a_profile_ranks_it_above_the_packages_it_layers_on.js +0 -34
  123. package/dist/esm/for_cratisComponentsPackage/when_a_profile_ranks_it_above_the_packages_it_layers_on.js.map +0 -1
  124. package/dist/esm/for_cratisComponentsPackage/when_declaring_command_form_peers.d.ts +0 -2
  125. package/dist/esm/for_cratisComponentsPackage/when_declaring_command_form_peers.d.ts.map +0 -1
  126. package/dist/esm/for_cratisComponentsPackage/when_declaring_command_form_peers.js +0 -16
  127. package/dist/esm/for_cratisComponentsPackage/when_declaring_command_form_peers.js.map +0 -1
  128. package/dist/esm/for_cratisComponentsPackage/when_describing_query_arguments.d.ts +0 -2
  129. package/dist/esm/for_cratisComponentsPackage/when_describing_query_arguments.d.ts.map +0 -1
  130. package/dist/esm/for_cratisComponentsPackage/when_describing_query_arguments.js +0 -11
  131. package/dist/esm/for_cratisComponentsPackage/when_describing_query_arguments.js.map +0 -1
  132. package/dist/esm/for_cratisComponentsPackage/when_describing_query_input_form.d.ts +0 -2
  133. package/dist/esm/for_cratisComponentsPackage/when_describing_query_input_form.d.ts.map +0 -1
  134. package/dist/esm/for_cratisComponentsPackage/when_describing_query_input_form.js +0 -14
  135. package/dist/esm/for_cratisComponentsPackage/when_describing_query_input_form.js.map +0 -1
  136. package/dist/esm/for_cratisComponentsPackage/when_describing_single_result.d.ts +0 -2
  137. package/dist/esm/for_cratisComponentsPackage/when_describing_single_result.d.ts.map +0 -1
  138. package/dist/esm/for_cratisComponentsPackage/when_describing_single_result.js +0 -16
  139. package/dist/esm/for_cratisComponentsPackage/when_describing_single_result.js.map +0 -1
  140. package/dist/esm/for_cratisComponentsPackage/when_resolving_its_dependencies.d.ts +0 -2
  141. package/dist/esm/for_cratisComponentsPackage/when_resolving_its_dependencies.d.ts.map +0 -1
  142. package/dist/esm/for_cratisComponentsPackage/when_resolving_its_dependencies.js +0 -49
  143. package/dist/esm/for_cratisComponentsPackage/when_resolving_its_dependencies.js.map +0 -1
  144. package/dist/esm/for_cratisComponentsPackage/when_validating_the_bundle.d.ts +0 -2
  145. package/dist/esm/for_cratisComponentsPackage/when_validating_the_bundle.d.ts.map +0 -1
  146. package/dist/esm/for_cratisComponentsPackage/when_validating_the_bundle.js +0 -27
  147. package/dist/esm/for_cratisComponentsPackage/when_validating_the_bundle.js.map +0 -1
  148. package/dist/esm/for_properties/when_a_property_has_the_wrong_type.d.ts +0 -2
  149. package/dist/esm/for_properties/when_a_property_has_the_wrong_type.d.ts.map +0 -1
  150. package/dist/esm/for_properties/when_a_property_has_the_wrong_type.js +0 -24
  151. package/dist/esm/for_properties/when_a_property_has_the_wrong_type.js.map +0 -1
  152. package/dist/esm/for_properties/when_a_property_is_missing.d.ts +0 -2
  153. package/dist/esm/for_properties/when_a_property_is_missing.d.ts.map +0 -1
  154. package/dist/esm/for_properties/when_a_property_is_missing.js +0 -13
  155. package/dist/esm/for_properties/when_a_property_is_missing.js.map +0 -1
  156. package/dist/esm/for_properties/when_a_property_is_present.d.ts +0 -2
  157. package/dist/esm/for_properties/when_a_property_is_present.d.ts.map +0 -1
  158. package/dist/esm/for_properties/when_a_property_is_present.js +0 -21
  159. package/dist/esm/for_properties/when_a_property_is_present.js.map +0 -1
  160. package/dist/esm/forms/fields/for_CommandFormField/when_the_field_names_no_property.d.ts +0 -2
  161. package/dist/esm/forms/fields/for_CommandFormField/when_the_field_names_no_property.d.ts.map +0 -1
  162. package/dist/esm/forms/fields/for_CommandFormField/when_the_field_names_no_property.js +0 -12
  163. package/dist/esm/forms/fields/for_CommandFormField/when_the_field_names_no_property.js.map +0 -1
  164. package/dist/esm/forms/fields/for_SceneRadioButtonField/when_mapping_the_group_name.d.ts +0 -2
  165. package/dist/esm/forms/fields/for_SceneRadioButtonField/when_mapping_the_group_name.d.ts.map +0 -1
  166. package/dist/esm/forms/fields/for_SceneRadioButtonField/when_mapping_the_group_name.js +0 -38
  167. package/dist/esm/forms/fields/for_SceneRadioButtonField/when_mapping_the_group_name.js.map +0 -1
  168. package/dist/esm/forms/fields/for_resolveFieldBinding/when_resolving_a_field_binding.d.ts +0 -2
  169. package/dist/esm/forms/fields/for_resolveFieldBinding/when_resolving_a_field_binding.d.ts.map +0 -1
  170. package/dist/esm/forms/fields/for_resolveFieldBinding/when_resolving_a_field_binding.js +0 -28
  171. package/dist/esm/forms/fields/for_resolveFieldBinding/when_resolving_a_field_binding.js.map +0 -1
  172. package/dist/esm/forms/for_SceneCommandForm/given/RecordNote.d.ts +0 -22
  173. package/dist/esm/forms/for_SceneCommandForm/given/RecordNote.d.ts.map +0 -1
  174. package/dist/esm/forms/for_SceneCommandForm/given/RecordNote.js +0 -30
  175. package/dist/esm/forms/for_SceneCommandForm/given/RecordNote.js.map +0 -1
  176. package/dist/esm/forms/for_SceneCommandForm/given/StartProject.d.ts +0 -32
  177. package/dist/esm/forms/for_SceneCommandForm/given/StartProject.d.ts.map +0 -1
  178. package/dist/esm/forms/for_SceneCommandForm/given/StartProject.js +0 -32
  179. package/dist/esm/forms/for_SceneCommandForm/given/StartProject.js.map +0 -1
  180. package/dist/esm/forms/for_SceneCommandForm/when_forwarding_to_the_lazy_runtime.d.ts +0 -2
  181. package/dist/esm/forms/for_SceneCommandForm/when_forwarding_to_the_lazy_runtime.d.ts.map +0 -1
  182. package/dist/esm/forms/for_SceneCommandForm/when_forwarding_to_the_lazy_runtime.js +0 -66
  183. package/dist/esm/forms/for_SceneCommandForm/when_forwarding_to_the_lazy_runtime.js.map +0 -1
  184. package/dist/esm/forms/for_SceneCommandForm/when_native_custom_field_errors_block_submission.d.ts +0 -2
  185. package/dist/esm/forms/for_SceneCommandForm/when_native_custom_field_errors_block_submission.d.ts.map +0 -1
  186. package/dist/esm/forms/for_SceneCommandForm/when_native_custom_field_errors_block_submission.js +0 -26
  187. package/dist/esm/forms/for_SceneCommandForm/when_native_custom_field_errors_block_submission.js.map +0 -1
  188. package/dist/esm/forms/for_SceneCommandForm/when_preserving_guid_error_ownership.d.ts +0 -2
  189. package/dist/esm/forms/for_SceneCommandForm/when_preserving_guid_error_ownership.d.ts.map +0 -1
  190. package/dist/esm/forms/for_SceneCommandForm/when_preserving_guid_error_ownership.js +0 -44
  191. package/dist/esm/forms/for_SceneCommandForm/when_preserving_guid_error_ownership.js.map +0 -1
  192. package/dist/esm/forms/for_SceneCommandForm/when_rendering_submit_in_native_context.d.ts +0 -2
  193. package/dist/esm/forms/for_SceneCommandForm/when_rendering_submit_in_native_context.d.ts.map +0 -1
  194. package/dist/esm/forms/for_SceneCommandForm/when_rendering_submit_in_native_context.js +0 -49
  195. package/dist/esm/forms/for_SceneCommandForm/when_rendering_submit_in_native_context.js.map +0 -1
  196. package/dist/esm/forms/for_SceneCommandForm/when_submitting_explicit_inputs.d.ts +0 -2
  197. package/dist/esm/forms/for_SceneCommandForm/when_submitting_explicit_inputs.d.ts.map +0 -1
  198. package/dist/esm/forms/for_SceneCommandForm/when_submitting_explicit_inputs.js +0 -176
  199. package/dist/esm/forms/for_SceneCommandForm/when_submitting_explicit_inputs.js.map +0 -1
  200. package/dist/esm/forms/for_SceneCommandForm/when_submitting_the_native_form.d.ts +0 -2
  201. package/dist/esm/forms/for_SceneCommandForm/when_submitting_the_native_form.d.ts.map +0 -1
  202. package/dist/esm/forms/for_SceneCommandForm/when_submitting_the_native_form.js +0 -110
  203. package/dist/esm/forms/for_SceneCommandForm/when_submitting_the_native_form.js.map +0 -1
  204. package/dist/esm/forms/for_SceneQueryInputForm/ProjectLookup.d.ts +0 -26
  205. package/dist/esm/forms/for_SceneQueryInputForm/ProjectLookup.d.ts.map +0 -1
  206. package/dist/esm/forms/for_SceneQueryInputForm/ProjectLookup.js +0 -44
  207. package/dist/esm/forms/for_SceneQueryInputForm/ProjectLookup.js.map +0 -1
  208. package/dist/esm/forms/for_SceneQueryInputForm/when_submitting_generated_guid_parameters.d.ts +0 -2
  209. package/dist/esm/forms/for_SceneQueryInputForm/when_submitting_generated_guid_parameters.d.ts.map +0 -1
  210. package/dist/esm/forms/for_SceneQueryInputForm/when_submitting_generated_guid_parameters.js +0 -175
  211. package/dist/esm/forms/for_SceneQueryInputForm/when_submitting_generated_guid_parameters.js.map +0 -1
  212. package/dist/esm/forms/for_SceneQueryInputForm/when_submitting_native_queries.d.ts +0 -2
  213. package/dist/esm/forms/for_SceneQueryInputForm/when_submitting_native_queries.d.ts.map +0 -1
  214. package/dist/esm/forms/for_SceneQueryInputForm/when_submitting_native_queries.js +0 -413
  215. package/dist/esm/forms/for_SceneQueryInputForm/when_submitting_native_queries.js.map +0 -1
  216. package/dist/esm/pages/for_ScenePage/when_rendering_a_page.d.ts +0 -2
  217. package/dist/esm/pages/for_ScenePage/when_rendering_a_page.d.ts.map +0 -1
  218. package/dist/esm/pages/for_ScenePage/when_rendering_a_page.js +0 -31
  219. package/dist/esm/pages/for_ScenePage/when_rendering_a_page.js.map +0 -1
  220. package/editors/for_SceneObjectNavigationalBar/when_navigating_back_up_the_trail.tsx +0 -24
  221. package/editors/for_filterDefinitions/when_reading_filter_definitions.ts +0 -49
  222. package/editors/for_timeMachineVersions/when_reading_versions.ts +0 -39
  223. package/for_cratisComponents/when_rendering_a_screen_through_the_real_renderer.tsx +0 -37
  224. package/for_cratisComponentsPackage/when_a_profile_ranks_it_above_the_packages_it_layers_on.ts +0 -49
  225. package/for_cratisComponentsPackage/when_declaring_command_form_peers.ts +0 -26
  226. package/for_cratisComponentsPackage/when_describing_query_arguments.ts +0 -15
  227. package/for_cratisComponentsPackage/when_describing_query_input_form.ts +0 -17
  228. package/for_cratisComponentsPackage/when_describing_single_result.ts +0 -20
  229. package/for_cratisComponentsPackage/when_resolving_its_dependencies.ts +0 -78
  230. package/for_cratisComponentsPackage/when_validating_the_bundle.ts +0 -39
  231. package/for_properties/when_a_property_has_the_wrong_type.ts +0 -41
  232. package/for_properties/when_a_property_is_missing.ts +0 -26
  233. package/for_properties/when_a_property_is_present.ts +0 -36
  234. package/forms/fields/for_CommandFormField/when_the_field_names_no_property.tsx +0 -16
  235. package/forms/fields/for_SceneRadioButtonField/when_mapping_the_group_name.tsx +0 -45
  236. package/forms/fields/for_resolveFieldBinding/when_resolving_a_field_binding.ts +0 -40
  237. package/forms/for_SceneCommandForm/given/RecordNote.ts +0 -37
  238. package/forms/for_SceneCommandForm/given/StartProject.ts +0 -41
  239. package/forms/for_SceneCommandForm/when_forwarding_to_the_lazy_runtime.tsx +0 -69
  240. package/forms/for_SceneCommandForm/when_native_custom_field_errors_block_submission.tsx +0 -33
  241. package/forms/for_SceneCommandForm/when_preserving_guid_error_ownership.tsx +0 -50
  242. package/forms/for_SceneCommandForm/when_rendering_submit_in_native_context.tsx +0 -56
  243. package/forms/for_SceneCommandForm/when_submitting_explicit_inputs.tsx +0 -189
  244. package/forms/for_SceneCommandForm/when_submitting_the_native_form.tsx +0 -120
  245. package/forms/for_SceneQueryInputForm/ProjectLookup.ts +0 -54
  246. package/forms/for_SceneQueryInputForm/when_submitting_generated_guid_parameters.tsx +0 -188
  247. package/forms/for_SceneQueryInputForm/when_submitting_native_queries.tsx +0 -423
  248. package/pages/for_ScenePage/when_rendering_a_page.tsx +0 -39
@@ -1,188 +0,0 @@
1
- // Copyright (c) Cratis. All rights reserved.
2
- // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
-
4
- import { act, cleanup, fireEvent, render, screen } from '@testing-library/react';
5
- import { expect, vi } from 'vitest';
6
- import { ArcContext } from '@cratis/arc.react';
7
- import { QueryFor } from '@cratis/arc/queries';
8
- import { ParameterDescriptor } from '@cratis/arc/reflection';
9
- import { Guid } from '@cratis/fundamentals';
10
- import { SceneElementView } from '@cratis/scene.react';
11
- import { clearBindings, registerQuery, registerQueryIdentity, unregisterQueryIdentity } from '../../bindings';
12
- import { cratisComponents } from '../../cratisComponents';
13
- import { externalComponent } from '../../given';
14
- import { ProjectById, ProjectByIdParameters } from './ProjectLookup';
15
-
16
- const projectId = 'AB123456-7890-4ABC-8DEF-1234567890AB';
17
- const input = { parameter: 'projectId', type: 'string', label: 'Project identifier' };
18
- const identity = 'Projects/Registration/ProjectLookup/ProjectLookup.ts:ProjectById';
19
- const context = { microservice: 'projects', origin: 'https://example.test', apiBasePath: '' };
20
-
21
- function response(data: unknown) {
22
- return { ok: true, status: 200, json: async () => ({
23
- data, isSuccess: true, isAuthorized: true, isValid: true, hasExceptions: false,
24
- validationResults: [], exceptionMessages: [], exceptionStackTrace: '',
25
- paging: { page: 0, size: 0, totalItems: 0, totalPages: 0 },
26
- }) } as Response;
27
- }
28
-
29
- function view(properties: Record<string, unknown> = {}, component = 'queryInputForm') {
30
- return <ArcContext.Provider value={context}>
31
- <SceneElementView element={externalComponent(`Cratis.Components:${component}`, {
32
- query: 'ProjectById', inputs: [input], resultField: 'name', ...properties,
33
- })} registry={cratisComponents} resolveBinding={() => undefined} />
34
- </ArcContext.Provider>;
35
- }
36
-
37
- async function submit(value = projectId) {
38
- fireEvent.change(screen.getByRole('textbox', { name: input.label }), { target: { value } });
39
- await act(async () => { fireEvent.submit(screen.getByRole('form')); });
40
- }
41
-
42
- describe('when submitting the canonical generated Guid proxy shape through SceneElementView', () => {
43
- const fetch = vi.fn<typeof globalThis.fetch>();
44
-
45
- beforeEach(() => {
46
- clearBindings();
47
- registerQueryIdentity('ProjectById', identity, ProjectById);
48
- fetch.mockReset();
49
- fetch.mockResolvedValue(response({ name: 'Canonical project', projectId }));
50
- vi.stubGlobal('fetch', fetch);
51
- });
52
-
53
- afterEach(() => { cleanup(); clearBindings(); vi.unstubAllGlobals(); });
54
-
55
- it('keeps the generated Guid contract and inherited native perform, sending exact entered text', async () => {
56
- const proxy = new ProjectById();
57
- expect(proxy.perform).toBe(QueryFor.prototype.perform);
58
- expect(proxy.parameterDescriptors).toEqual([new ParameterDescriptor('projectId', Guid, false)]);
59
- expect(proxy.requiredRequestParameters).toEqual(['projectId']);
60
- expect(proxy.defaultValue).toEqual({});
61
- expect(proxy.queryName).toBe('CanonicalProjects.Projects.Registration.ProjectLookup.ProjectSummary.ProjectById');
62
- render(view());
63
- expect(fetch).not.toHaveBeenCalled();
64
- await submit();
65
- expect(await screen.findByText('Canonical project')).not.toBeNull();
66
- expect(fetch).toHaveBeenCalledTimes(1);
67
- const [url, init] = fetch.mock.calls[0];
68
- expect(String(url)).toBe(`https://example.test/api/projects/registration/project-lookup/project-by-id?projectId=${projectId}`);
69
- expect(init?.method).toBe('GET');
70
- expect(new URL(String(url)).searchParams.get('projectId')).toBe(projectId);
71
- expect(screen.getByRole('textbox')).toHaveProperty('value', projectId);
72
- });
73
-
74
- for (const data of [null, undefined]) {
75
- it(`preserves native absence (${String(data)}) despite the generated empty-object default`, async () => {
76
- fetch.mockResolvedValue(response(data));
77
- render(view()); await submit();
78
- expect(await screen.findByText('Not found')).not.toBeNull();
79
- expect(fetch).toHaveBeenCalledTimes(1);
80
- });
81
- }
82
-
83
- it('does not claim Guid descriptors enforce format: native perform sends an unformatted string unchanged', async () => {
84
- render(view()); await submit(' not-a-guid ');
85
- expect(await screen.findByText('Canonical project')).not.toBeNull();
86
- expect(new URL(String(fetch.mock.calls[0][0])).searchParams.get('projectId')).toBe(' not-a-guid ');
87
- });
88
-
89
- it('lets an explicitly supplied pattern reject invalid Guid text before HTTP and permit correction', async () => {
90
- render(view({ inputs: [{ ...input, pattern: '[0-9a-fA-F]{8}(?:-[0-9a-fA-F]{4}){3}-[0-9a-fA-F]{12}' }] }));
91
- await submit('not-a-guid');
92
- expect(screen.getByRole('alert').textContent).toBe('Project identifier has an invalid format');
93
- expect(fetch).not.toHaveBeenCalled();
94
- expect(screen.getByRole('textbox')).toHaveProperty('value', 'not-a-guid');
95
- await submit();
96
- expect(await screen.findByText('Canonical project')).not.toBeNull();
97
- expect(new URL(String(fetch.mock.calls[0][0])).searchParams.get('projectId')).toBe(projectId);
98
- });
99
-
100
- it('retains native required-argument validation when the form permits an empty string', async () => {
101
- render(view({ inputs: [{ ...input, required: false }] })); await submit('');
102
- expect(await screen.findByRole('alert')).toHaveProperty('textContent', 'Unable to load result');
103
- expect(fetch).not.toHaveBeenCalled();
104
- });
105
-
106
- for (const descriptors of [
107
- [new ParameterDescriptor('projectId', Number, false)],
108
- [new ParameterDescriptor('projectId', Boolean, false)],
109
- [new ParameterDescriptor('projectId', Object, false)],
110
- [new ParameterDescriptor('projectId', Guid, true)],
111
- [new ParameterDescriptor('projectId', String, true)],
112
- [new ParameterDescriptor('ProjectID', Guid, false)],
113
- [],
114
- [new ParameterDescriptor('projectId', Guid, false), new ParameterDescriptor('projectId', String, false)],
115
- ]) {
116
- it(`rejects unsupported descriptor mapping before HTTP: ${descriptors.map(d => `${d.name}:${d.type.name}:${d.isEnumerable}`).join(',')}`, async () => {
117
- class Incompatible extends ProjectById { readonly parameterDescriptors = descriptors; }
118
- registerQueryIdentity('ProjectById', identity, Incompatible);
119
- render(view()); await submit();
120
- expect(await screen.findByRole('alert')).toHaveProperty('textContent', 'Unable to load result');
121
- expect(screen.getByRole('textbox')).toHaveProperty('value', projectId);
122
- expect(fetch).not.toHaveBeenCalled();
123
- });
124
- }
125
-
126
- it('rejects an unknown extra parameter even when every required native argument is present', async () => {
127
- render(view({ inputs: [input, { parameter: 'unknown', type: 'string', label: 'Unknown', required: false }] }));
128
- await submit();
129
- expect(await screen.findByRole('alert')).toHaveProperty('textContent', 'Unable to load result');
130
- expect(fetch).not.toHaveBeenCalled();
131
- });
132
-
133
- it('demonstrates why native descriptor mapping alone cannot protect the form', async () => {
134
- class Numeric extends ProjectById {
135
- readonly parameterDescriptors = [new ParameterDescriptor('projectId', Number, false)];
136
- }
137
- const proxy = new Numeric();
138
- proxy.setOrigin(context.origin);
139
- // Deliberate runtime mismatch, NOT a change to the emitted consumer's parameter interface.
140
- const args = { projectId: 'not-a-number', unknown: 'extra' } as unknown as ProjectByIdParameters;
141
- const result = await proxy.perform(args);
142
- expect(result.isSuccess).toBe(true);
143
- expect(fetch).toHaveBeenCalledTimes(1);
144
- const url = new URL(String(fetch.mock.calls[0][0]));
145
- expect(url.searchParams.get('projectId')).toBe('not-a-number');
146
- expect(url.searchParams.get('unknown')).toBe('extra');
147
- });
148
-
149
- it('allows an identity-only registration to serve an existing singleResult with the same semantic name', async () => {
150
- render(view({ queryArguments: { projectId }, enabled: true }, 'singleResult'));
151
- expect(await screen.findByText('Canonical project')).not.toBeNull();
152
- expect(new URL(String(fetch.mock.calls[0][0])).searchParams.get('projectId')).toBe(projectId);
153
- });
154
-
155
- it('fails visibly without selecting an ambiguous identity in an existing singleResult', () => {
156
- registerQueryIdentity('ProjectById', 'Other/ProjectById', ProjectById);
157
- render(view({ queryArguments: { projectId }, enabled: true }, 'singleResult'));
158
- expect(screen.getByText("Unresolved query binding 'ProjectById' on Cratis.Components:singleResult")).not.toBeNull();
159
- expect(fetch).not.toHaveBeenCalled();
160
- });
161
-
162
- it('resolves identity replacement and removal on an existing adapter host rerender', async () => {
163
- const mounted = render(view({ queryArguments: { projectId }, enabled: true }, 'singleResult'));
164
- expect(await screen.findByText('Canonical project')).not.toBeNull();
165
- class Replacement extends ProjectById { readonly route = '/replacement'; }
166
- act(() => { registerQueryIdentity('ProjectById', identity, Replacement); });
167
- mounted.rerender(view({ queryArguments: { projectId }, enabled: true }, 'singleResult'));
168
- await screen.findByText('Canonical project');
169
- expect(fetch).toHaveBeenCalledTimes(2);
170
- expect(new URL(String(fetch.mock.calls[1][0])).pathname).toBe('/replacement');
171
- act(() => { unregisterQueryIdentity('ProjectById', identity); });
172
- mounted.rerender(view({ queryArguments: { projectId }, enabled: true }, 'singleResult'));
173
- expect(screen.getByText("Unresolved query binding 'ProjectById' on Cratis.Components:singleResult")).not.toBeNull();
174
- expect(fetch).toHaveBeenCalledTimes(2);
175
- });
176
-
177
- it('keeps legacy replacement authoritative for singleResult while queryInputForm rejects mixed candidates', async () => {
178
- class Legacy extends ProjectById { readonly route = '/legacy'; }
179
- registerQuery('ProjectById', ProjectById);
180
- registerQuery('ProjectById', Legacy);
181
- const mounted = render(view({ queryArguments: { projectId }, enabled: true }, 'singleResult'));
182
- expect(await screen.findByText('Canonical project')).not.toBeNull();
183
- expect(new URL(String(fetch.mock.calls[0][0])).pathname).toBe('/legacy');
184
- mounted.rerender(view());
185
- expect(screen.getByRole('alert').textContent).toContain("Ambiguous query binding 'ProjectById'");
186
- expect(fetch).toHaveBeenCalledTimes(1);
187
- });
188
- });
@@ -1,423 +0,0 @@
1
- // Copyright (c) Cratis. All rights reserved.
2
- // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
-
4
- import { act, cleanup, fireEvent, render, screen, waitFor } from '@testing-library/react';
5
- import { expect, vi } from 'vitest';
6
- import { ArcContext, type ArcConfiguration } from '@cratis/arc.react';
7
- import { QueryFor, QueryHttpMethod, QueryValidator } from '@cratis/arc/queries';
8
- import { ParameterDescriptor } from '@cratis/arc/reflection';
9
- import { SceneElementView } from '@cratis/scene.react';
10
- import { clearBindings, registerQuery, registerQueryIdentity, unregisterQueryIdentity } from '../../bindings';
11
- import { cratisComponents } from '../../cratisComponents';
12
- import { externalComponent } from '../../given';
13
-
14
- class ArgumentsValidator extends QueryValidator<{ projectId: string }> {
15
- static received: object[] = [];
16
- constructor() {
17
- super();
18
- this.ruleFor(args => {
19
- // ruleFor first invokes the accessor on a property-name discovery proxy, not request data.
20
- if (Object.hasOwn(args, 'projectId')) ArgumentsValidator.received.push(args);
21
- return args.projectId;
22
- }).minLength(2);
23
- }
24
- }
25
-
26
- // Native published Arc perform, required argument checks, validator, routing and deserialization.
27
- // Only fetch is substituted; neither the renderer nor any runtime/primitive is mocked.
28
- class ProjectName extends QueryFor<object | undefined, { projectId: string }> {
29
- readonly route = '/projects/{projectId}/name';
30
- readonly requiredRequestParameters = ['projectId'];
31
- readonly parameterDescriptors = [
32
- new ParameterDescriptor('projectId', String, false),
33
- new ParameterDescriptor('locale', String, false),
34
- new ParameterDescriptor('toString', String, false),
35
- ];
36
- readonly validation = new ArgumentsValidator();
37
- defaultValue = undefined;
38
- constructor() {
39
- super(Object, false);
40
- this.setHttpMethod(QueryHttpMethod.Get);
41
- // Model an unset descriptor-backed instance slot, not Object.prototype.toString:
42
- // native Arc collects instance values as well as the explicit perform arguments.
43
- Object.defineProperty(this, 'toString', { value: undefined });
44
- }
45
- }
46
-
47
- class AllProjects extends QueryFor<object[]> {
48
- readonly route = '/projects';
49
- readonly requiredRequestParameters = [];
50
- readonly parameterDescriptors = [];
51
- defaultValue = [];
52
- constructor() { super(Object, true); this.setHttpMethod(QueryHttpMethod.Get); }
53
- }
54
-
55
- function response(data: unknown, overrides: Record<string, unknown> = {}) {
56
- return { ok: true, status: 200, json: async () => ({
57
- data, isSuccess: true, isAuthorized: true, isValid: true, hasExceptions: false,
58
- validationResults: [], exceptionMessages: [], exceptionStackTrace: '',
59
- paging: { page: 0, size: 0, totalItems: 0, totalPages: 0 }, ...overrides,
60
- }) } as Response;
61
- }
62
-
63
- function deferred() {
64
- let resolve!: (response: Response) => void;
65
- const promise = new Promise<Response>(yes => { resolve = yes; });
66
- return { promise, resolve };
67
- }
68
-
69
- const input = { parameter: 'projectId', type: 'string', label: 'Project identifier' };
70
- const context: ArcConfiguration = {
71
- microservice: 'projects', origin: 'https://example.test', apiBasePath: '/backend',
72
- httpHeadersCallback: () => ({ 'x-host': 'original' }),
73
- };
74
-
75
- function view(properties: Record<string, unknown> = {}, arc = context, isEnabled = true) {
76
- const element = { ...externalComponent('Cratis.Components:queryInputForm', {
77
- query: 'ProjectName', inputs: [input], resultField: 'name', ...properties,
78
- }), isEnabled };
79
- return <ArcContext.Provider value={arc}>
80
- <SceneElementView element={element} registry={cratisComponents} resolveBinding={() => undefined} />
81
- </ArcContext.Provider>;
82
- }
83
-
84
- function edit(value: string, label = 'Project identifier') {
85
- fireEvent.change(screen.getByRole('textbox', { name: label }), { target: { value } });
86
- }
87
-
88
- async function submit() {
89
- await act(async () => { fireEvent.click(screen.getByRole('button', { name: 'Search' })); });
90
- }
91
-
92
- describe('when submitting query inputs through SceneElementView and native Arc', () => {
93
- const fetch = vi.fn<typeof globalThis.fetch>();
94
-
95
- beforeEach(() => {
96
- clearBindings();
97
- registerQueryIdentity('ProjectName', 'Queries/ProjectName', ProjectName);
98
- registerQuery('AllProjects', AllProjects);
99
- ArgumentsValidator.received = [];
100
- fetch.mockReset();
101
- fetch.mockResolvedValue(response({ name: 'Project result' }));
102
- vi.stubGlobal('fetch', fetch);
103
- });
104
-
105
- afterEach(() => { cleanup(); clearBindings(); vi.unstubAllGlobals(); });
106
-
107
- it('starts empty, never executes while editing, and commits exact named strings in an immutable snapshot', async () => {
108
- render(view({ inputs: [input, { parameter: 'locale', type: 'string', label: 'Locale', required: false }] }));
109
- expect(screen.getByRole('textbox', { name: input.label })).toHaveProperty('value', '');
110
- edit(' exact-ID ');
111
- edit(' nb & en ', 'Locale');
112
- expect(fetch).not.toHaveBeenCalled();
113
- expect(ArgumentsValidator.received).toHaveLength(0);
114
- await submit();
115
- expect(await screen.findByText('Project result')).not.toBeNull();
116
- expect(fetch).toHaveBeenCalledTimes(1);
117
- const [url, init] = fetch.mock.calls[0];
118
- expect(String(url)).toBe('https://example.test/backend/projects/%20%20exact-ID%20%20/name?locale=+nb+%26+en+');
119
- expect(new Headers(init?.headers).get('x-host')).toBe('original');
120
- expect(new Headers(init?.headers).get('x-cratis-microservice')).toBe('projects');
121
- const snapshot = ArgumentsValidator.received[0];
122
- expect(snapshot).toEqual({ projectId: ' exact-ID ', locale: ' nb & en ' });
123
- expect(Object.isFrozen(snapshot)).toBe(true);
124
- edit('different');
125
- expect(screen.queryByText('Project result')).toBeNull();
126
- expect(snapshot).toEqual({ projectId: ' exact-ID ', locale: ' nb & en ' });
127
- expect(fetch).toHaveBeenCalledTimes(1);
128
- });
129
-
130
- it('uses the native form submit event (also emitted by implicit Enter submission)', async () => {
131
- render(view());
132
- edit('entered-id');
133
- // jsdom does not implement implicit keyboard submission; dispatch its native submit event.
134
- await act(async () => { fireEvent.submit(screen.getByRole('form', { name: 'Query input' })); });
135
- expect(await screen.findByText('Project result')).not.toBeNull();
136
- expect(String(fetch.mock.calls[0][0])).toContain('/entered-id/name');
137
- });
138
-
139
- for (const blank of ['', ' ', '\t']) {
140
- it(`shows required input feedback without performing for ${JSON.stringify(blank)}`, async () => {
141
- render(view());
142
- edit(blank);
143
- await submit();
144
- expect(screen.getByRole('alert').textContent).toBe('Project identifier is required');
145
- const control = screen.getByRole('textbox', { name: input.label });
146
- expect(control.getAttribute('aria-invalid')).toBe('true');
147
- expect(control.getAttribute('aria-describedby')).toBe(screen.getByRole('alert').id);
148
- expect(ArgumentsValidator.received).toHaveLength(0);
149
- expect(fetch).not.toHaveBeenCalled();
150
- });
151
- }
152
-
153
- it('validates an explicitly declared whole-string format without coercion and allows correction', async () => {
154
- render(view({ inputs: [{ ...input, pattern: '[A-Z]{2}-[0-9]{2}' }] }));
155
- edit(' xx-12 ');
156
- await submit();
157
- expect(screen.getByRole('alert').textContent).toBe('Project identifier has an invalid format');
158
- expect(fetch).not.toHaveBeenCalled();
159
- expect(ArgumentsValidator.received).toHaveLength(0);
160
- expect(screen.getByRole('textbox')).toHaveProperty('value', ' xx-12 ');
161
- edit('AB-12');
162
- await submit();
163
- expect(await screen.findByText('Project result')).not.toBeNull();
164
- expect(ArgumentsValidator.received[0]).toEqual({ projectId: 'AB-12' });
165
- });
166
-
167
- for (const value of ['12\n', '12\r', '12\r\n', '12\u2028', '12\u2029']) {
168
- it(`rejects a final line terminator in whole-string patterns: ${JSON.stringify(value)}`, async () => {
169
- // Without the multiline flag JS $ requires the actual end. Native text controls
170
- // sanitize CR/LF; inject a raw value to exercise validation without that help.
171
- expect(/^(?:[0-9]+)$/u.test(value)).toBe(false);
172
- render(view({ inputs: [{ ...input, pattern: '[0-9]+' }] }));
173
- const control = screen.getByRole('textbox');
174
- Object.defineProperty(control, 'value', { configurable: true, get: () => value });
175
- fireEvent.change(control);
176
- await submit();
177
- expect(screen.getByRole('alert').textContent).toBe('Project identifier has an invalid format');
178
- expect(control).toHaveProperty('value', value);
179
- expect(ArgumentsValidator.received).toHaveLength(0);
180
- expect(fetch).not.toHaveBeenCalled();
181
- });
182
- }
183
-
184
- it('preserves an explicitly allowed newline through validation and native HTTP', async () => {
185
- const value = '12\n';
186
- render(view({ inputs: [{ ...input, pattern: '[0-9]+\\s' }] }));
187
- const control = screen.getByRole('textbox');
188
- Object.defineProperty(control, 'value', { configurable: true, get: () => value });
189
- fireEvent.change(control);
190
- await submit();
191
- expect(await screen.findByText('Project result')).not.toBeNull();
192
- expect(ArgumentsValidator.received[0]).toEqual({ projectId: value });
193
- expect(String(fetch.mock.calls[0][0])).toContain('/12%0A/name');
194
- });
195
-
196
- it('lets native validation reject without HTTP, retains drafts, and allows retry after correction', async () => {
197
- render(view());
198
- edit('x');
199
- await submit();
200
- expect(await screen.findByRole('alert')).toHaveProperty('textContent', 'Unable to load result');
201
- expect(fetch).not.toHaveBeenCalled();
202
- expect(ArgumentsValidator.received[0]).toEqual({ projectId: 'x' });
203
- expect(screen.getByRole('textbox')).toHaveProperty('value', 'x');
204
- edit('xx');
205
- await submit();
206
- expect(await screen.findByText('Project result')).not.toBeNull();
207
- expect(fetch).toHaveBeenCalledTimes(1);
208
- });
209
-
210
- it('does not guess parameter names when a declaration mismatches the proxy', async () => {
211
- render(view({ inputs: [{ ...input, parameter: 'ProjectID' }] }));
212
- edit('explicit-id');
213
- await submit();
214
- expect(await screen.findByRole('alert')).toHaveProperty('textContent', 'Unable to load result');
215
- expect(fetch).not.toHaveBeenCalled();
216
- });
217
-
218
- for (const data of [null, undefined]) {
219
- it(`shows not found for a successful ${String(data)} model and permits repeat submit`, async () => {
220
- fetch.mockResolvedValueOnce(response(data));
221
- render(view()); edit('missing-id'); await submit();
222
- expect(await screen.findByText('Not found')).not.toBeNull();
223
- await submit();
224
- expect(await screen.findByText('Project result')).not.toBeNull();
225
- expect(fetch).toHaveBeenCalledTimes(2);
226
- expect(ArgumentsValidator.received[0]).toEqual(ArgumentsValidator.received[1]);
227
- expect(ArgumentsValidator.received[0]).not.toBe(ArgumentsValidator.received[1]);
228
- });
229
- }
230
-
231
- it('allows retry of unchanged input after transport failure', async () => {
232
- fetch.mockRejectedValueOnce(new Error('private network details'));
233
- render(view()); edit('retry-id'); await submit();
234
- expect(await screen.findByRole('alert')).toHaveProperty('textContent', 'Unable to load result');
235
- expect(document.body.textContent).not.toContain('private network details');
236
- await submit();
237
- expect(await screen.findByText('Project result')).not.toBeNull();
238
- expect(fetch).toHaveBeenCalledTimes(2);
239
- });
240
-
241
- for (const failure of [{ isValid: false }, { isAuthorized: false }, { isSuccess: false }, { hasExceptions: true }]) {
242
- it(`preserves native failure precedence for ${JSON.stringify(failure)}`, async () => {
243
- fetch.mockResolvedValue(response(null, { ...failure, exceptionMessages: ['secret'] }));
244
- render(view()); edit('valid-id'); await submit();
245
- expect(await screen.findByRole('alert')).toHaveProperty('textContent', 'Unable to load result');
246
- expect(screen.queryByText('Not found')).toBeNull();
247
- expect(document.body.textContent).not.toContain('secret');
248
- });
249
- }
250
-
251
- it('aborts on edit and ignores stale response after a newer submission even when HTTP ignores abort', async () => {
252
- const a = deferred(); const b = deferred();
253
- fetch.mockReturnValueOnce(a.promise).mockReturnValueOnce(b.promise);
254
- render(view()); edit('first'); await submit();
255
- const signal = fetch.mock.calls[0][1]?.signal;
256
- edit('second');
257
- expect(signal?.aborted).toBe(true);
258
- expect(screen.getByText('Idle')).not.toBeNull();
259
- expect(fetch).toHaveBeenCalledTimes(1);
260
- await submit();
261
- await act(async () => { b.resolve(response({ name: 'Second result' })); });
262
- await act(async () => { a.resolve(response({ name: 'Obsolete result' })); });
263
- expect(screen.getByText('Second result')).not.toBeNull();
264
- expect(screen.queryByText('Obsolete result')).toBeNull();
265
- });
266
-
267
- it('never resurrects a result by editing back to the previously submitted value', async () => {
268
- render(view()); edit('first'); await submit();
269
- expect(await screen.findByText('Project result')).not.toBeNull();
270
- edit('second'); edit('first');
271
- expect(screen.queryByText('Project result')).toBeNull();
272
- expect(screen.getByText('Idle')).not.toBeNull();
273
- expect(fetch).toHaveBeenCalledTimes(1);
274
- });
275
-
276
- it('ignores a pending result after edit without a second submit', async () => {
277
- const pending = deferred(); fetch.mockReturnValueOnce(pending.promise);
278
- render(view()); edit('first'); await submit(); edit('second');
279
- await act(async () => { pending.resolve(response({ name: 'Obsolete result' })); });
280
- expect(screen.queryByText('Obsolete result')).toBeNull();
281
- expect(screen.getByText('Idle')).not.toBeNull();
282
- });
283
-
284
- it('aborts on unmount and ignores successful late completion', async () => {
285
- const pending = deferred(); fetch.mockReturnValueOnce(pending.promise);
286
- const mounted = render(view()); edit('first'); await submit();
287
- mounted.unmount();
288
- expect(fetch.mock.calls[0][1]?.signal?.aborted).toBe(true);
289
- await act(async () => { pending.resolve(response({ name: 'Disposed result' })); });
290
- expect(screen.queryByText('Disposed result')).toBeNull();
291
- });
292
-
293
- it('reuses runtime invalidation when Arc context headers change', async () => {
294
- const pending = deferred();
295
- const mounted = render(view()); edit('first'); await submit();
296
- expect(await screen.findByText('Project result')).not.toBeNull();
297
- fetch.mockReturnValueOnce(pending.promise);
298
- mounted.rerender(view({}, { ...context, httpHeadersCallback: () => ({ 'x-host': 'new' }) }));
299
- expect(screen.queryByText('Project result')).toBeNull();
300
- await waitFor(() => expect(fetch).toHaveBeenCalledTimes(2));
301
- expect(new Headers(fetch.mock.calls[1][1]?.headers).get('x-host')).toBe('new');
302
- await act(async () => { pending.resolve(response({ name: 'New context' })); });
303
- expect(screen.getByText('New context')).not.toBeNull();
304
- });
305
-
306
- for (const query of [undefined, 'Missing', 'projectname']) {
307
- it(`visibly fails exact missing binding ${String(query)} without choosing AllProjects`, () => {
308
- render(view({ query }));
309
- expect(screen.getByText(query ? `Unresolved query binding '${query}' on Cratis.Components:queryInputForm` : 'Missing query binding on Cratis.Components:queryInputForm')).not.toBeNull();
310
- expect(screen.queryByRole('textbox')).toBeNull();
311
- expect(fetch).not.toHaveBeenCalled();
312
- });
313
- }
314
-
315
- it('shows ambiguous identity registrations and never chooses a candidate', () => {
316
- registerQueryIdentity('ProjectName', 'Other/ProjectName', ProjectName);
317
- render(view());
318
- expect(screen.getByRole('alert').textContent).toContain("Ambiguous query binding 'ProjectName'");
319
- expect(screen.queryByRole('textbox')).toBeNull();
320
- expect(fetch).not.toHaveBeenCalled();
321
- });
322
-
323
- it('fails closed and cancels when a mounted binding becomes ambiguous, then starts fresh on resolution', async () => {
324
- const pending = deferred(); fetch.mockReturnValueOnce(pending.promise);
325
- render(view()); edit('first'); await submit();
326
- act(() => { registerQueryIdentity('ProjectName', 'Other/ProjectName', ProjectName); });
327
- expect(screen.getByRole('alert').textContent).toContain('Ambiguous query binding');
328
- expect(fetch.mock.calls[0][1]?.signal?.aborted).toBe(true);
329
- await act(async () => { pending.resolve(response({ name: 'Obsolete result' })); });
330
- act(() => { unregisterQueryIdentity('ProjectName', 'Other/ProjectName'); });
331
- expect(screen.getByRole('textbox')).toHaveProperty('value', '');
332
- expect(screen.queryByText('Obsolete result')).toBeNull();
333
- expect(fetch).toHaveBeenCalledTimes(1);
334
- });
335
-
336
- it('accepts legacy registration replacement without making it ambiguous', async () => {
337
- clearBindings();
338
- registerQuery('ProjectName', AllProjects);
339
- registerQuery('ProjectName', ProjectName);
340
- render(view()); edit('legacy-id'); await submit();
341
- expect(await screen.findByText('Project result')).not.toBeNull();
342
- expect(fetch).toHaveBeenCalledTimes(1);
343
- });
344
-
345
- it('replaces a mounted source identity on hot reload using the runtime cancellation contract', async () => {
346
- const pending = deferred(); fetch.mockReturnValueOnce(pending.promise);
347
- render(view()); edit('reload-id'); await submit();
348
- class Replacement extends ProjectName {}
349
- await act(async () => { registerQueryIdentity('ProjectName', 'Queries/ProjectName', Replacement); });
350
- expect(fetch.mock.calls[0][1]?.signal?.aborted).toBe(true);
351
- expect(await screen.findByText('Project result')).not.toBeNull();
352
- await act(async () => { pending.resolve(response({ name: 'Obsolete result' })); });
353
- expect(screen.queryByText('Obsolete result')).toBeNull();
354
- expect(fetch).toHaveBeenCalledTimes(2);
355
- expect(ArgumentsValidator.received[0]).toBe(ArgumentsValidator.received[1]);
356
- });
357
-
358
- it('includes optional empty strings verbatim and supports exact own names without prototype lookup', async () => {
359
- render(view({ inputs: [input, { parameter: 'toString', type: 'string', label: 'Optional input', required: false }] }));
360
- edit('some-id'); await submit();
361
- expect(await screen.findByText('Project result')).not.toBeNull();
362
- expect(ArgumentsValidator.received[0]).toEqual({ projectId: 'some-id', toString: '' });
363
- expect(new URL(String(fetch.mock.calls[0][0])).searchParams.get('toString')).toBe('');
364
- });
365
-
366
- it('still runs native required-argument validation when a declared optional string is empty', async () => {
367
- render(view({ inputs: [{ ...input, required: false }] }));
368
- await submit();
369
- expect(await screen.findByRole('alert')).toHaveProperty('textContent', 'Unable to load result');
370
- expect(fetch).not.toHaveBeenCalled();
371
- });
372
-
373
- it('allows an unchanged pending submission to be superseded by an explicit retry', async () => {
374
- const pending = deferred(); fetch.mockReturnValueOnce(pending.promise);
375
- render(view()); edit('retry-id'); await submit();
376
- await submit();
377
- expect(fetch.mock.calls[0][1]?.signal?.aborted).toBe(true);
378
- expect(await screen.findByText('Project result')).not.toBeNull();
379
- await act(async () => { pending.resolve(response({ name: 'Old attempt' })); });
380
- expect(screen.queryByText('Old attempt')).toBeNull();
381
- expect(fetch).toHaveBeenCalledTimes(2);
382
- });
383
-
384
- it('rejects an enumerable proxy before native perform rather than falling back to a collection', async () => {
385
- render(view({ query: 'AllProjects' })); edit('not-used'); await submit();
386
- expect(await screen.findByRole('alert')).toHaveProperty('textContent', 'Unable to load result');
387
- expect(fetch).not.toHaveBeenCalled();
388
- });
389
-
390
- for (const inputs of [undefined, [], {}, [null], [{ ...input, type: 'number' }], [input, input], [{ ...input, parameter: '' }], [{ ...input, label: 7 }], [{ ...input, required: 'true' }], [{ ...input, pattern: '[' }], [{ ...input, pattern: 7 }]]) {
391
- it(`rejects malformed declarations ${JSON.stringify(inputs)} visibly without native execution`, () => {
392
- render(view({ inputs }));
393
- expect(screen.getByRole('alert').textContent).toBe('Invalid query input form configuration');
394
- expect(screen.queryByRole('textbox')).toBeNull();
395
- expect(fetch).not.toHaveBeenCalled();
396
- expect(ArgumentsValidator.received).toHaveLength(0);
397
- });
398
- }
399
-
400
- it('retains drafts across equivalent host rerenders but resets on a new declaration', async () => {
401
- const mounted = render(view()); edit('draft');
402
- mounted.rerender(view());
403
- expect(screen.getByRole('textbox')).toHaveProperty('value', 'draft');
404
- await submit();
405
- expect(await screen.findByText('Project result')).not.toBeNull();
406
- mounted.rerender(view({ inputs: [{ ...input, label: 'New identifier' }] }));
407
- expect(screen.getByRole('textbox')).toHaveProperty('value', '');
408
- expect(screen.queryByText('Project result')).toBeNull();
409
- expect(fetch).toHaveBeenCalledTimes(1);
410
- });
411
-
412
- it('cancels and clears the session when the element is disabled', async () => {
413
- const pending = deferred(); fetch.mockReturnValueOnce(pending.promise);
414
- const mounted = render(view()); edit('first'); await submit();
415
- mounted.rerender(view({}, context, false));
416
- expect(fetch.mock.calls[0][1]?.signal?.aborted).toBe(true);
417
- await act(async () => { pending.resolve(response({ name: 'Obsolete result' })); });
418
- expect(screen.queryByText('Obsolete result')).toBeNull();
419
- mounted.rerender(view());
420
- expect(screen.getByRole('textbox')).toHaveProperty('value', '');
421
- expect(fetch).toHaveBeenCalledTimes(1);
422
- });
423
- });
@@ -1,39 +0,0 @@
1
- // Copyright (c) Cratis. All rights reserved.
2
- // Licensed under the MIT license. See LICENSE file in the project root for full license information.
3
-
4
- import { expect } from 'chai';
5
- import { render, screen } from '@testing-library/react';
6
- import { externalComponent } from '../../given';
7
- import { ScenePage } from '../ScenePage';
8
-
9
- describe('when rendering a page', () => {
10
- describe('and the screen asks for the title to be shown', () => {
11
- beforeEach(() => {
12
- const element = externalComponent('Cratis.Components:page', { title: 'Invoices', showTitle: true });
13
- render(<ScenePage element={element} slots={{ content: [<span key='body'>Body</span>] }} />);
14
- });
15
-
16
- it('should render the title as the heading', () => expect(screen.getByRole('heading', { name: 'Invoices' })).to.exist);
17
- it('should render the content slot', () => expect(screen.getByText('Body')).to.exist);
18
- });
19
-
20
- describe('and the screen leaves the title hidden', () => {
21
- beforeEach(() => {
22
- const element = externalComponent('Cratis.Components:page', { title: 'Invoices' });
23
- render(<ScenePage element={element} slots={{ content: [<span key='body'>Body</span>] }} />);
24
- });
25
-
26
- it('should render no heading', () => (screen.queryByRole('heading') === null).should.be.true);
27
- it('should still render the content slot', () => expect(screen.getByText('Body')).to.exist);
28
- });
29
-
30
- describe('and the screen sets the title to something that is not a string', () => {
31
- beforeEach(() => {
32
- const element = externalComponent('Cratis.Components:page', { title: 42, showTitle: true });
33
- render(<ScenePage element={element} slots={{}} />);
34
- });
35
-
36
- it('should fall back to an empty title rather than rendering the wrong type', () =>
37
- screen.getByRole('heading').textContent!.should.equal(''));
38
- });
39
- });