@solidxai/core 0.1.2 → 0.1.5-beta.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 (469) hide show
  1. package/.claude/settings.local.json +8 -0
  2. package/dist/commands/run-tests.command.d.ts +37 -0
  3. package/dist/commands/run-tests.command.d.ts.map +1 -0
  4. package/dist/commands/run-tests.command.js +345 -0
  5. package/dist/commands/run-tests.command.js.map +1 -0
  6. package/dist/commands/test-data.command.d.ts +6 -6
  7. package/dist/commands/test-data.command.d.ts.map +1 -1
  8. package/dist/commands/test-data.command.js +25 -25
  9. package/dist/commands/test-data.command.js.map +1 -1
  10. package/dist/commands/test.command.d.ts +5 -0
  11. package/dist/commands/test.command.d.ts.map +1 -0
  12. package/dist/commands/test.command.js +26 -0
  13. package/dist/commands/test.command.js.map +1 -0
  14. package/dist/constants/error-messages.d.ts +1 -0
  15. package/dist/constants/error-messages.d.ts.map +1 -1
  16. package/dist/constants/error-messages.js +1 -0
  17. package/dist/constants/error-messages.js.map +1 -1
  18. package/dist/constants.d.ts +3 -3
  19. package/dist/constants.d.ts.map +1 -1
  20. package/dist/constants.js +12 -12
  21. package/dist/constants.js.map +1 -1
  22. package/dist/controllers/otp-authentication.controller.d.ts +1 -4
  23. package/dist/controllers/otp-authentication.controller.d.ts.map +1 -1
  24. package/dist/controllers/otp-authentication.controller.js +1 -1
  25. package/dist/controllers/role-metadata.controller.d.ts +1 -0
  26. package/dist/controllers/role-metadata.controller.d.ts.map +1 -1
  27. package/dist/controllers/role-metadata.controller.js +15 -0
  28. package/dist/controllers/role-metadata.controller.js.map +1 -1
  29. package/dist/controllers/service.controller.d.ts +0 -9
  30. package/dist/controllers/service.controller.d.ts.map +1 -1
  31. package/dist/controllers/service.controller.js +0 -45
  32. package/dist/controllers/service.controller.js.map +1 -1
  33. package/dist/dtos/basic-filters.dto.d.ts.map +1 -1
  34. package/dist/dtos/basic-filters.dto.js.map +1 -1
  35. package/dist/dtos/create-email-template.dto.d.ts.map +1 -1
  36. package/dist/dtos/create-email-template.dto.js.map +1 -1
  37. package/dist/dtos/create-list-of-values.dto.d.ts.map +1 -1
  38. package/dist/dtos/create-list-of-values.dto.js.map +1 -1
  39. package/dist/dtos/create-menu-item-metadata.dto.d.ts.map +1 -1
  40. package/dist/dtos/create-menu-item-metadata.dto.js.map +1 -1
  41. package/dist/dtos/create-role-metadata.dto.d.ts.map +1 -1
  42. package/dist/dtos/create-role-metadata.dto.js.map +1 -1
  43. package/dist/dtos/create-scheduled-job.dto.d.ts.map +1 -1
  44. package/dist/dtos/create-scheduled-job.dto.js.map +1 -1
  45. package/dist/dtos/create-security-rule.dto.d.ts.map +1 -1
  46. package/dist/dtos/create-security-rule.dto.js.map +1 -1
  47. package/dist/dtos/create-sms-template.dto.d.ts.map +1 -1
  48. package/dist/dtos/create-sms-template.dto.js.map +1 -1
  49. package/dist/dtos/create-user.dto.d.ts +1 -0
  50. package/dist/dtos/create-user.dto.d.ts.map +1 -1
  51. package/dist/dtos/create-user.dto.js +2 -1
  52. package/dist/dtos/create-user.dto.js.map +1 -1
  53. package/dist/dtos/create-view-metadata.dto.d.ts.map +1 -1
  54. package/dist/dtos/create-view-metadata.dto.js.map +1 -1
  55. package/dist/dtos/otp-sign-in.dto.d.ts +1 -1
  56. package/dist/dtos/otp-sign-in.dto.d.ts.map +1 -1
  57. package/dist/dtos/otp-sign-in.dto.js +2 -2
  58. package/dist/dtos/otp-sign-in.dto.js.map +1 -1
  59. package/dist/dtos/otp-sign-up.dto.d.ts +2 -2
  60. package/dist/dtos/otp-sign-up.dto.d.ts.map +1 -1
  61. package/dist/dtos/otp-sign-up.dto.js +2 -2
  62. package/dist/dtos/otp-sign-up.dto.js.map +1 -1
  63. package/dist/dtos/resolve-s3-url.dto.d.ts +2 -5
  64. package/dist/dtos/resolve-s3-url.dto.d.ts.map +1 -1
  65. package/dist/dtos/resolve-s3-url.dto.js +1 -13
  66. package/dist/dtos/resolve-s3-url.dto.js.map +1 -1
  67. package/dist/dtos/sign-up.dto.d.ts.map +1 -1
  68. package/dist/dtos/sign-up.dto.js.map +1 -1
  69. package/dist/dtos/update-email-template.dto.d.ts.map +1 -1
  70. package/dist/dtos/update-email-template.dto.js.map +1 -1
  71. package/dist/dtos/update-list-of-values.dto.d.ts.map +1 -1
  72. package/dist/dtos/update-list-of-values.dto.js.map +1 -1
  73. package/dist/dtos/update-menu-item-metadata.dto.d.ts.map +1 -1
  74. package/dist/dtos/update-menu-item-metadata.dto.js.map +1 -1
  75. package/dist/dtos/update-scheduled-job.dto.d.ts.map +1 -1
  76. package/dist/dtos/update-scheduled-job.dto.js.map +1 -1
  77. package/dist/dtos/update-security-rule.dto.d.ts.map +1 -1
  78. package/dist/dtos/update-security-rule.dto.js.map +1 -1
  79. package/dist/dtos/update-sms-template.dto.d.ts.map +1 -1
  80. package/dist/dtos/update-sms-template.dto.js.map +1 -1
  81. package/dist/dtos/update-view-metadata.dto.d.ts.map +1 -1
  82. package/dist/dtos/update-view-metadata.dto.js.map +1 -1
  83. package/dist/entities/user.entity.d.ts +1 -0
  84. package/dist/entities/user.entity.d.ts.map +1 -1
  85. package/dist/entities/user.entity.js +6 -1
  86. package/dist/entities/user.entity.js.map +1 -1
  87. package/dist/helpers/field-crud-managers/ManyToManyRelationFieldCrudManager.d.ts +2 -0
  88. package/dist/helpers/field-crud-managers/ManyToManyRelationFieldCrudManager.d.ts.map +1 -1
  89. package/dist/helpers/field-crud-managers/ManyToManyRelationFieldCrudManager.js +33 -23
  90. package/dist/helpers/field-crud-managers/ManyToManyRelationFieldCrudManager.js.map +1 -1
  91. package/dist/helpers/field-crud-managers/OneToManyRelationFieldCrudManager.d.ts +3 -0
  92. package/dist/helpers/field-crud-managers/OneToManyRelationFieldCrudManager.d.ts.map +1 -1
  93. package/dist/helpers/field-crud-managers/OneToManyRelationFieldCrudManager.js +36 -23
  94. package/dist/helpers/field-crud-managers/OneToManyRelationFieldCrudManager.js.map +1 -1
  95. package/dist/helpers/security.helper.js +1 -0
  96. package/dist/helpers/security.helper.js.map +1 -1
  97. package/dist/index.d.ts +3 -4
  98. package/dist/index.d.ts.map +1 -1
  99. package/dist/index.js +3 -4
  100. package/dist/index.js.map +1 -1
  101. package/dist/repository/solid-base.repository.d.ts +10 -1
  102. package/dist/repository/solid-base.repository.d.ts.map +1 -1
  103. package/dist/repository/solid-base.repository.js +109 -0
  104. package/dist/repository/solid-base.repository.js.map +1 -1
  105. package/dist/seeders/module-metadata-seeder.service.d.ts +2 -0
  106. package/dist/seeders/module-metadata-seeder.service.d.ts.map +1 -1
  107. package/dist/seeders/module-metadata-seeder.service.js +142 -91
  108. package/dist/seeders/module-metadata-seeder.service.js.map +1 -1
  109. package/dist/seeders/module-test-data.service.d.ts.map +1 -1
  110. package/dist/seeders/module-test-data.service.js +3 -3
  111. package/dist/seeders/module-test-data.service.js.map +1 -1
  112. package/dist/seeders/permission-metadata-seeder.service.d.ts +1 -1
  113. package/dist/seeders/permission-metadata-seeder.service.d.ts.map +1 -1
  114. package/dist/seeders/permission-metadata-seeder.service.js +1 -1
  115. package/dist/seeders/permission-metadata-seeder.service.js.map +1 -1
  116. package/dist/seeders/seed-data/solid-core-metadata.json +12 -25
  117. package/dist/services/authentication.service.d.ts +22 -8
  118. package/dist/services/authentication.service.d.ts.map +1 -1
  119. package/dist/services/authentication.service.js +228 -214
  120. package/dist/services/authentication.service.js.map +1 -1
  121. package/dist/services/chatter-message.service.d.ts +2 -0
  122. package/dist/services/chatter-message.service.d.ts.map +1 -1
  123. package/dist/services/chatter-message.service.js +18 -2
  124. package/dist/services/chatter-message.service.js.map +1 -1
  125. package/dist/services/crud-helper.service.d.ts +4 -0
  126. package/dist/services/crud-helper.service.d.ts.map +1 -1
  127. package/dist/services/crud-helper.service.js +66 -32
  128. package/dist/services/crud-helper.service.js.map +1 -1
  129. package/dist/services/crud.service.d.ts.map +1 -1
  130. package/dist/services/crud.service.js +7 -4
  131. package/dist/services/crud.service.js.map +1 -1
  132. package/dist/services/field-metadata.service.d.ts.map +1 -1
  133. package/dist/services/field-metadata.service.js.map +1 -1
  134. package/dist/services/file/disk-file.service.d.ts +0 -2
  135. package/dist/services/file/disk-file.service.d.ts.map +1 -1
  136. package/dist/services/file/disk-file.service.js +7 -16
  137. package/dist/services/file/disk-file.service.js.map +1 -1
  138. package/dist/services/file/index.d.ts +1 -0
  139. package/dist/services/file/index.d.ts.map +1 -1
  140. package/dist/services/file/index.js +1 -0
  141. package/dist/services/file/index.js.map +1 -1
  142. package/dist/services/file/storage-path-builder.d.ts +17 -0
  143. package/dist/services/file/storage-path-builder.d.ts.map +1 -0
  144. package/dist/{seeders/sms-template-seeder.service.js → services/file/storage-path-builder.js} +45 -35
  145. package/dist/services/file/storage-path-builder.js.map +1 -0
  146. package/dist/services/media.service.d.ts +1 -1
  147. package/dist/services/media.service.d.ts.map +1 -1
  148. package/dist/services/media.service.js +45 -6
  149. package/dist/services/media.service.js.map +1 -1
  150. package/dist/services/mediaStorageProviders/file-s3-storage-provider.js.map +1 -1
  151. package/dist/services/mediaStorageProviders/file-storage-provider.d.ts.map +1 -1
  152. package/dist/services/mediaStorageProviders/file-storage-provider.js +46 -7
  153. package/dist/services/mediaStorageProviders/file-storage-provider.js.map +1 -1
  154. package/dist/services/module-metadata.service.d.ts +4 -6
  155. package/dist/services/module-metadata.service.d.ts.map +1 -1
  156. package/dist/services/module-metadata.service.js +16 -14
  157. package/dist/services/module-metadata.service.js.map +1 -1
  158. package/dist/services/queues/common.d.ts +3 -0
  159. package/dist/services/queues/common.d.ts.map +1 -0
  160. package/dist/services/queues/common.js +39 -0
  161. package/dist/services/queues/common.js.map +1 -0
  162. package/dist/services/queues/database-publisher.service.d.ts.map +1 -1
  163. package/dist/services/queues/database-publisher.service.js +3 -1
  164. package/dist/services/queues/database-publisher.service.js.map +1 -1
  165. package/dist/services/queues/database-subscriber.service.d.ts.map +1 -1
  166. package/dist/services/queues/database-subscriber.service.js +5 -2
  167. package/dist/services/queues/database-subscriber.service.js.map +1 -1
  168. package/dist/services/queues/rabbitmq-publisher.service.d.ts.map +1 -1
  169. package/dist/services/queues/rabbitmq-publisher.service.js +13 -6
  170. package/dist/services/queues/rabbitmq-publisher.service.js.map +1 -1
  171. package/dist/services/queues/rabbitmq-subscriber.service.d.ts.map +1 -1
  172. package/dist/services/queues/rabbitmq-subscriber.service.js +9 -5
  173. package/dist/services/queues/rabbitmq-subscriber.service.js.map +1 -1
  174. package/dist/services/setting.service.d.ts +3 -2
  175. package/dist/services/setting.service.d.ts.map +1 -1
  176. package/dist/services/setting.service.js +7 -4
  177. package/dist/services/setting.service.js.map +1 -1
  178. package/dist/services/settings/default-settings-provider.service.d.ts +24 -2
  179. package/dist/services/settings/default-settings-provider.service.d.ts.map +1 -1
  180. package/dist/services/settings/default-settings-provider.service.js +8 -6
  181. package/dist/services/settings/default-settings-provider.service.js.map +1 -1
  182. package/dist/solid-core.module.d.ts +3 -1
  183. package/dist/solid-core.module.d.ts.map +1 -1
  184. package/dist/solid-core.module.js +49 -9
  185. package/dist/solid-core.module.js.map +1 -1
  186. package/dist/testing/__examples__/register-example-specs.d.ts +3 -0
  187. package/dist/testing/__examples__/register-example-specs.d.ts.map +1 -0
  188. package/dist/testing/__examples__/register-example-specs.js +8 -0
  189. package/dist/testing/__examples__/register-example-specs.js.map +1 -0
  190. package/dist/testing/__examples__/specs/custom-health.spec.d.ts +17 -0
  191. package/dist/testing/__examples__/specs/custom-health.spec.d.ts.map +1 -0
  192. package/dist/testing/__examples__/specs/custom-health.spec.js +30 -0
  193. package/dist/testing/__examples__/specs/custom-health.spec.js.map +1 -0
  194. package/dist/testing/adapters/api/api-adapter.d.ts +9 -0
  195. package/dist/testing/adapters/api/api-adapter.d.ts.map +1 -0
  196. package/dist/testing/adapters/api/api-adapter.js +76 -0
  197. package/dist/testing/adapters/api/api-adapter.js.map +1 -0
  198. package/dist/testing/adapters/api/api.types.d.ts +14 -0
  199. package/dist/testing/adapters/api/api.types.d.ts.map +1 -0
  200. package/dist/testing/adapters/api/api.types.js +3 -0
  201. package/dist/testing/adapters/api/api.types.js.map +1 -0
  202. package/dist/testing/adapters/ui/playwright-adapter.d.ts +14 -0
  203. package/dist/testing/adapters/ui/playwright-adapter.d.ts.map +1 -0
  204. package/dist/testing/adapters/ui/playwright-adapter.js +80 -0
  205. package/dist/testing/adapters/ui/playwright-adapter.js.map +1 -0
  206. package/dist/testing/adapters/ui/ui.types.d.ts +5 -0
  207. package/dist/testing/adapters/ui/ui.types.d.ts.map +1 -0
  208. package/dist/testing/adapters/ui/ui.types.js +3 -0
  209. package/dist/testing/adapters/ui/ui.types.js.map +1 -0
  210. package/dist/testing/contracts/runtime-context.types.d.ts +35 -0
  211. package/dist/testing/contracts/runtime-context.types.d.ts.map +1 -0
  212. package/dist/testing/contracts/runtime-context.types.js +3 -0
  213. package/dist/testing/contracts/runtime-context.types.js.map +1 -0
  214. package/dist/testing/contracts/test-spec.types.d.ts +21 -0
  215. package/dist/testing/contracts/test-spec.types.d.ts.map +1 -0
  216. package/dist/testing/contracts/test-spec.types.js +3 -0
  217. package/dist/testing/contracts/test-spec.types.js.map +1 -0
  218. package/dist/testing/contracts/testing-metadata.types.d.ts +41 -0
  219. package/dist/testing/contracts/testing-metadata.types.d.ts.map +1 -0
  220. package/dist/testing/contracts/testing-metadata.types.js +3 -0
  221. package/dist/testing/contracts/testing-metadata.types.js.map +1 -0
  222. package/dist/testing/core/interpolation.d.ts +4 -0
  223. package/dist/testing/core/interpolation.d.ts.map +1 -0
  224. package/dist/testing/core/interpolation.js +180 -0
  225. package/dist/testing/core/interpolation.js.map +1 -0
  226. package/dist/testing/core/normalize-steps.d.ts +7 -0
  227. package/dist/testing/core/normalize-steps.d.ts.map +1 -0
  228. package/dist/testing/core/normalize-steps.js +20 -0
  229. package/dist/testing/core/normalize-steps.js.map +1 -0
  230. package/dist/testing/core/resource-store.d.ts +8 -0
  231. package/dist/testing/core/resource-store.d.ts.map +1 -0
  232. package/dist/testing/core/resource-store.js +41 -0
  233. package/dist/testing/core/resource-store.js.map +1 -0
  234. package/dist/testing/core/spec-registry.d.ts +10 -0
  235. package/dist/testing/core/spec-registry.d.ts.map +1 -0
  236. package/dist/testing/core/spec-registry.js +32 -0
  237. package/dist/testing/core/spec-registry.js.map +1 -0
  238. package/dist/testing/core/step-registry.d.ts +10 -0
  239. package/dist/testing/core/step-registry.d.ts.map +1 -0
  240. package/dist/testing/core/step-registry.js +26 -0
  241. package/dist/testing/core/step-registry.js.map +1 -0
  242. package/dist/testing/core/testing-engine.d.ts +14 -0
  243. package/dist/testing/core/testing-engine.d.ts.map +1 -0
  244. package/dist/testing/core/testing-engine.js +97 -0
  245. package/dist/testing/core/testing-engine.js.map +1 -0
  246. package/dist/testing/core/timeout.d.ts +2 -0
  247. package/dist/testing/core/timeout.d.ts.map +1 -0
  248. package/dist/testing/core/timeout.js +18 -0
  249. package/dist/testing/core/timeout.js.map +1 -0
  250. package/dist/testing/reporter/attachments.d.ts +4 -0
  251. package/dist/testing/reporter/attachments.d.ts.map +1 -0
  252. package/dist/testing/reporter/attachments.js +25 -0
  253. package/dist/testing/reporter/attachments.js.map +1 -0
  254. package/dist/testing/reporter/console-reporter.d.ts +45 -0
  255. package/dist/testing/reporter/console-reporter.d.ts.map +1 -0
  256. package/dist/testing/reporter/console-reporter.js +189 -0
  257. package/dist/testing/reporter/console-reporter.js.map +1 -0
  258. package/dist/testing/reporter/reporter.types.d.ts +37 -0
  259. package/dist/testing/reporter/reporter.types.d.ts.map +1 -0
  260. package/dist/testing/reporter/reporter.types.js +3 -0
  261. package/dist/testing/reporter/reporter.types.js.map +1 -0
  262. package/dist/testing/runner/lifecycle.d.ts +9 -0
  263. package/dist/testing/runner/lifecycle.d.ts.map +1 -0
  264. package/dist/testing/runner/lifecycle.js +33 -0
  265. package/dist/testing/runner/lifecycle.js.map +1 -0
  266. package/dist/testing/runner/run-from-metadata.d.ts +24 -0
  267. package/dist/testing/runner/run-from-metadata.d.ts.map +1 -0
  268. package/dist/testing/runner/run-from-metadata.js +70 -0
  269. package/dist/testing/runner/run-from-metadata.js.map +1 -0
  270. package/dist/testing/runner/scenario-filter.d.ts +9 -0
  271. package/dist/testing/runner/scenario-filter.d.ts.map +1 -0
  272. package/dist/testing/runner/scenario-filter.js +22 -0
  273. package/dist/testing/runner/scenario-filter.js.map +1 -0
  274. package/dist/testing/steps/api/auth.step.d.ts +3 -0
  275. package/dist/testing/steps/api/auth.step.d.ts.map +1 -0
  276. package/dist/testing/steps/api/auth.step.js +38 -0
  277. package/dist/testing/steps/api/auth.step.js.map +1 -0
  278. package/dist/testing/steps/api/index.d.ts +3 -0
  279. package/dist/testing/steps/api/index.d.ts.map +1 -0
  280. package/dist/testing/steps/api/index.js +10 -0
  281. package/dist/testing/steps/api/index.js.map +1 -0
  282. package/dist/testing/steps/api/request.step.d.ts +3 -0
  283. package/dist/testing/steps/api/request.step.d.ts.map +1 -0
  284. package/dist/testing/steps/api/request.step.js +281 -0
  285. package/dist/testing/steps/api/request.step.js.map +1 -0
  286. package/dist/testing/steps/assert/http.step.d.ts +3 -0
  287. package/dist/testing/steps/assert/http.step.d.ts.map +1 -0
  288. package/dist/testing/steps/assert/http.step.js +27 -0
  289. package/dist/testing/steps/assert/http.step.js.map +1 -0
  290. package/dist/testing/steps/assert/index.d.ts +3 -0
  291. package/dist/testing/steps/assert/index.d.ts.map +1 -0
  292. package/dist/testing/steps/assert/index.js +12 -0
  293. package/dist/testing/steps/assert/index.js.map +1 -0
  294. package/dist/testing/steps/assert/jsonpath.step.d.ts +3 -0
  295. package/dist/testing/steps/assert/jsonpath.step.d.ts.map +1 -0
  296. package/dist/testing/steps/assert/jsonpath.step.js +40 -0
  297. package/dist/testing/steps/assert/jsonpath.step.js.map +1 -0
  298. package/dist/testing/steps/assert/primitives.step.d.ts +3 -0
  299. package/dist/testing/steps/assert/primitives.step.d.ts.map +1 -0
  300. package/dist/testing/steps/assert/primitives.step.js +43 -0
  301. package/dist/testing/steps/assert/primitives.step.js.map +1 -0
  302. package/dist/testing/steps/test/index.d.ts +3 -0
  303. package/dist/testing/steps/test/index.d.ts.map +1 -0
  304. package/dist/testing/steps/test/index.js +8 -0
  305. package/dist/testing/steps/test/index.js.map +1 -0
  306. package/dist/testing/steps/test/test-spec.step.d.ts +3 -0
  307. package/dist/testing/steps/test/test-spec.step.d.ts.map +1 -0
  308. package/dist/testing/steps/test/test-spec.step.js +41 -0
  309. package/dist/testing/steps/test/test-spec.step.js.map +1 -0
  310. package/dist/testing/steps/ui/actions.step.d.ts +3 -0
  311. package/dist/testing/steps/ui/actions.step.d.ts.map +1 -0
  312. package/dist/testing/steps/ui/actions.step.js +31 -0
  313. package/dist/testing/steps/ui/actions.step.js.map +1 -0
  314. package/dist/testing/steps/ui/assertions.step.d.ts +3 -0
  315. package/dist/testing/steps/ui/assertions.step.d.ts.map +1 -0
  316. package/dist/testing/steps/ui/assertions.step.js +41 -0
  317. package/dist/testing/steps/ui/assertions.step.js.map +1 -0
  318. package/dist/testing/steps/ui/form.step.d.ts +3 -0
  319. package/dist/testing/steps/ui/form.step.d.ts.map +1 -0
  320. package/dist/testing/steps/ui/form.step.js +34 -0
  321. package/dist/testing/steps/ui/form.step.js.map +1 -0
  322. package/dist/testing/steps/ui/index.d.ts +3 -0
  323. package/dist/testing/steps/ui/index.d.ts.map +1 -0
  324. package/dist/testing/steps/ui/index.js +14 -0
  325. package/dist/testing/steps/ui/index.js.map +1 -0
  326. package/dist/testing/steps/ui/navigation.step.d.ts +3 -0
  327. package/dist/testing/steps/ui/navigation.step.d.ts.map +1 -0
  328. package/dist/testing/steps/ui/navigation.step.js +39 -0
  329. package/dist/testing/steps/ui/navigation.step.js.map +1 -0
  330. package/dist/testing/steps/util/index.d.ts +3 -0
  331. package/dist/testing/steps/util/index.d.ts.map +1 -0
  332. package/dist/testing/steps/util/index.js +12 -0
  333. package/dist/testing/steps/util/index.js.map +1 -0
  334. package/dist/testing/steps/util/log.step.d.ts +3 -0
  335. package/dist/testing/steps/util/log.step.d.ts.map +1 -0
  336. package/dist/testing/steps/util/log.step.js +18 -0
  337. package/dist/testing/steps/util/log.step.js.map +1 -0
  338. package/dist/testing/steps/util/require.step.d.ts +3 -0
  339. package/dist/testing/steps/util/require.step.d.ts.map +1 -0
  340. package/dist/testing/steps/util/require.step.js +16 -0
  341. package/dist/testing/steps/util/require.step.js.map +1 -0
  342. package/dist/testing/steps/util/sleep.step.d.ts +3 -0
  343. package/dist/testing/steps/util/sleep.step.d.ts.map +1 -0
  344. package/dist/testing/steps/util/sleep.step.js +13 -0
  345. package/dist/testing/steps/util/sleep.step.js.map +1 -0
  346. package/docs/test-data-workflow.md +51 -11
  347. package/package.json +10 -2
  348. package/src/commands/run-tests.command.ts +278 -0
  349. package/src/commands/test-data.command.ts +26 -26
  350. package/src/commands/test.command.ts +14 -0
  351. package/src/constants/error-messages.ts +1 -0
  352. package/src/constants.ts +3 -3
  353. package/src/controllers/role-metadata.controller.ts +26 -18
  354. package/src/controllers/service.controller.ts +58 -59
  355. package/src/dtos/basic-filters.dto.ts +0 -2
  356. package/src/dtos/create-email-template.dto.ts +7 -0
  357. package/src/dtos/create-list-of-values.dto.ts +7 -0
  358. package/src/dtos/create-menu-item-metadata.dto.ts +12 -1
  359. package/src/dtos/create-role-metadata.dto.ts +9 -0
  360. package/src/dtos/create-scheduled-job.dto.ts +14 -0
  361. package/src/dtos/create-security-rule.dto.ts +6 -0
  362. package/src/dtos/create-sms-template.dto.ts +6 -0
  363. package/src/dtos/create-user.dto.ts +1 -0
  364. package/src/dtos/create-view-metadata.dto.ts +11 -0
  365. package/src/dtos/otp-sign-in.dto.ts +3 -3
  366. package/src/dtos/otp-sign-up.dto.ts +3 -3
  367. package/src/dtos/resolve-s3-url.dto.ts +2 -12
  368. package/src/dtos/sign-up.dto.ts +0 -2
  369. package/src/dtos/update-email-template.dto.ts +6 -0
  370. package/src/dtos/update-list-of-values.dto.ts +8 -0
  371. package/src/dtos/update-menu-item-metadata.dto.ts +12 -0
  372. package/src/dtos/update-scheduled-job.dto.ts +15 -0
  373. package/src/dtos/update-security-rule.dto.ts +7 -0
  374. package/src/dtos/update-sms-template.dto.ts +32 -32
  375. package/src/dtos/update-view-metadata.dto.ts +12 -0
  376. package/src/entities/user.entity.ts +3 -0
  377. package/src/helpers/field-crud-managers/ManyToManyRelationFieldCrudManager.ts +43 -32
  378. package/src/helpers/field-crud-managers/OneToManyRelationFieldCrudManager.ts +45 -33
  379. package/src/helpers/security.helper.ts +1 -1
  380. package/src/index.ts +3 -4
  381. package/src/repository/solid-base.repository.ts +172 -1
  382. package/src/seeders/module-metadata-seeder.service.ts +191 -150
  383. package/src/seeders/module-test-data.service.ts +5 -3
  384. package/src/seeders/permission-metadata-seeder.service.ts +1 -4
  385. package/src/seeders/seed-data/solid-core-metadata.json +12 -25
  386. package/src/services/authentication.service.ts +268 -266
  387. package/src/services/chatter-message.service.ts +18 -1
  388. package/src/services/crud-helper.service.ts +79 -36
  389. package/src/services/crud.service.ts +10 -4
  390. package/src/services/field-metadata.service.ts +0 -71
  391. package/src/services/file/disk-file.service.ts +8 -18
  392. package/src/services/file/index.ts +1 -0
  393. package/src/services/file/storage-path-builder.ts +56 -0
  394. package/src/services/media.service.ts +13 -7
  395. package/src/services/mediaStorageProviders/file-s3-storage-provider.ts +1 -1
  396. package/src/services/mediaStorageProviders/file-storage-provider.ts +13 -8
  397. package/src/services/module-metadata.service.ts +18 -15
  398. package/src/services/queues/common.ts +75 -0
  399. package/src/services/queues/database-publisher.service.ts +4 -1
  400. package/src/services/queues/database-subscriber.service.ts +5 -3
  401. package/src/services/queues/rabbitmq-publisher.service.ts +17 -7
  402. package/src/services/queues/rabbitmq-subscriber.service.ts +9 -5
  403. package/src/services/setting.service.ts +5 -3
  404. package/src/services/settings/default-settings-provider.service.ts +5 -3
  405. package/src/solid-core.module.ts +20 -12
  406. package/src/testing/README.md +364 -0
  407. package/src/testing/__examples__/register-example-specs.ts +6 -0
  408. package/src/testing/__examples__/specs/custom-health.spec.ts +29 -0
  409. package/src/testing/__examples__/testing.sample.json +82 -0
  410. package/src/testing/adapters/api/api-adapter.ts +85 -0
  411. package/src/testing/adapters/api/api.types.ts +15 -0
  412. package/src/testing/adapters/ui/playwright-adapter.ts +54 -0
  413. package/src/testing/adapters/ui/ui.types.ts +4 -0
  414. package/src/testing/contracts/runtime-context.types.ts +36 -0
  415. package/src/testing/contracts/test-spec.types.ts +24 -0
  416. package/src/testing/contracts/testing-metadata.types.ts +46 -0
  417. package/src/testing/core/interpolation.ts +189 -0
  418. package/src/testing/core/normalize-steps.ts +21 -0
  419. package/src/testing/core/resource-store.ts +38 -0
  420. package/src/testing/core/spec-registry.ts +33 -0
  421. package/src/testing/core/step-registry.ts +27 -0
  422. package/src/testing/core/testing-engine.ts +127 -0
  423. package/src/testing/core/timeout.ts +19 -0
  424. package/src/testing/reporter/attachments.ts +25 -0
  425. package/src/testing/reporter/console-reporter.ts +229 -0
  426. package/src/testing/reporter/reporter.types.ts +36 -0
  427. package/src/testing/runner/lifecycle.ts +31 -0
  428. package/src/testing/runner/run-from-metadata.ts +87 -0
  429. package/src/testing/runner/scenario-filter.ts +33 -0
  430. package/src/testing/steps/api/auth.step.ts +66 -0
  431. package/src/testing/steps/api/index.ts +10 -0
  432. package/src/testing/steps/api/request.step.ts +358 -0
  433. package/src/testing/steps/assert/http.step.ts +33 -0
  434. package/src/testing/steps/assert/index.ts +12 -0
  435. package/src/testing/steps/assert/jsonpath.step.ts +50 -0
  436. package/src/testing/steps/assert/primitives.step.ts +69 -0
  437. package/src/testing/steps/test/index.ts +8 -0
  438. package/src/testing/steps/test/test-spec.step.ts +52 -0
  439. package/src/testing/steps/ui/actions.step.ts +36 -0
  440. package/src/testing/steps/ui/assertions.step.ts +54 -0
  441. package/src/testing/steps/ui/form.step.ts +39 -0
  442. package/src/testing/steps/ui/index.ts +12 -0
  443. package/src/testing/steps/ui/navigation.step.ts +53 -0
  444. package/src/testing/steps/util/index.ts +10 -0
  445. package/src/testing/steps/util/log.step.ts +19 -0
  446. package/src/testing/steps/util/require.step.ts +16 -0
  447. package/src/testing/steps/util/sleep.step.ts +15 -0
  448. package/tsconfig.json +35 -25
  449. package/tsconfig.tests.json +14 -0
  450. package/dist/passport-strategies/local.strategy.d.ts +0 -15
  451. package/dist/passport-strategies/local.strategy.d.ts.map +0 -1
  452. package/dist/passport-strategies/local.strategy.js +0 -44
  453. package/dist/passport-strategies/local.strategy.js.map +0 -1
  454. package/dist/seeders/email-template-seeder.service.d.ts +0 -10
  455. package/dist/seeders/email-template-seeder.service.d.ts.map +0 -1
  456. package/dist/seeders/email-template-seeder.service.js +0 -84
  457. package/dist/seeders/email-template-seeder.service.js.map +0 -1
  458. package/dist/seeders/sms-template-seeder.service.d.ts +0 -10
  459. package/dist/seeders/sms-template-seeder.service.d.ts.map +0 -1
  460. package/dist/seeders/sms-template-seeder.service.js.map +0 -1
  461. package/dist/seeders/user-seeder.service.d.ts +0 -10
  462. package/dist/seeders/user-seeder.service.d.ts.map +0 -1
  463. package/dist/seeders/user-seeder.service.js +0 -44
  464. package/dist/seeders/user-seeder.service.js.map +0 -1
  465. package/dist/tsconfig.tsbuildinfo +0 -1
  466. package/src/passport-strategies/local.strategy.ts +0 -28
  467. package/src/seeders/email-template-seeder.service.ts +0 -49
  468. package/src/seeders/sms-template-seeder.service.ts +0 -50
  469. package/src/seeders/user-seeder.service.ts +0 -33
@@ -0,0 +1,364 @@
1
+ # Testing Module
2
+
3
+ ## Folder Structure
4
+ - `contracts/`: metadata + runtime context types
5
+ - `core/`: engine, registry, interpolation, utilities
6
+ - `adapters/`: API (axios) and UI (Playwright) adapters
7
+ - `steps/`: step implementations grouped by domain
8
+ - `reporter/`: reporting interfaces + console reporter
9
+ - `runner/`: lifecycle helpers + metadata runner
10
+
11
+ ## Metadata Shape
12
+ `TestingMetadata` lives under `testing` in module metadata JSON files.
13
+
14
+ ```json
15
+ {
16
+ "testing": {
17
+ "specs": ["path/to/register-test-specs.js"],
18
+ "data": [
19
+ {
20
+ "modelUserKey": "stateMaster",
21
+ "recUserKeyValue": "Maharashtra",
22
+ "data": {
23
+ "name": "Maharashtra",
24
+ "description": "State of Maharashtra"
25
+ }
26
+ }
27
+ ],
28
+ "scenarios": [
29
+ {
30
+ "id": "api-authenticate-success",
31
+ "name": "Authenticate succeeds",
32
+ "type": "api",
33
+ "params": {
34
+ "username": "alice"
35
+ },
36
+ "tags": ["smoke"],
37
+ "timeoutMs": 30000,
38
+ "retries": 1,
39
+ "steps": [
40
+ { "given": { "op": "api.request", "with": { "method": "POST", "url": "..." } } }
41
+ ]
42
+ }
43
+ ]
44
+ }
45
+ }
46
+ ```
47
+
48
+ ## Step Shape
49
+ Steps can be written as Given/When/Then blocks or as flat ops.
50
+
51
+ ```ts
52
+ {
53
+ id: "login-happy-path",
54
+ type: "ui",
55
+ steps: [
56
+ { given: { op: "ui.goto", with: { url: "/login" } } },
57
+ { when: { op: "ui.fill", with: { selector: "#user", value: "alice" } } },
58
+ { and: { op: "ui.fill", with: { selector: "#pass", value: "secret" } } },
59
+ { then: { op: "ui.click", with: { selector: "button[type=submit]" } } }
60
+ ]
61
+ }
62
+ ```
63
+
64
+ General step fields:
65
+ - `op` (required): operation name
66
+ - `with` (optional): op-specific options
67
+ - `saveAs` (optional): store the return value in the resource store (read via `${res:...}`)
68
+ - `name` (optional): label for reporting
69
+ - `timeoutMs` (optional): per-step timeout override
70
+ - `spec` (optional): used by `test.spec` to identify the spec
71
+
72
+ ## Interpolation
73
+ Available tokens:
74
+ - `${env:NAME}` (environment variables)
75
+ - `${params.foo}` (scenario params)
76
+ - `${res:saveAs.path}` (saved step results)
77
+ - `${data:modelUserKey["recUserKeyValue"].field}` (test data from `testing.data`)
78
+ - `${data:modelUserKey["recUserKeyValue"]._rec}` (raw record object when used alone)
79
+
80
+ Test data lookup details:
81
+ - Data is indexed as `data:<modelUserKey>["<recUserKeyValue>"]`.
82
+ - You can access fields with `.fieldName`.
83
+ - Bracket syntax is recommended for keys with spaces or punctuation.
84
+ - Use `._rec` to return the full object when the token is the entire value.
85
+ - `data.` is still supported for backward compatibility, but `data:` is preferred.
86
+
87
+ Examples:
88
+ ```json
89
+ {
90
+ "params": {
91
+ "state": "${data:stateMaster["Maharashtra"].name}"
92
+ },
93
+ "steps": [
94
+ {
95
+ "given": {
96
+ "op": "api.request",
97
+ "with": {
98
+ "method": "POST",
99
+ "url": "${env:API_BASE_URL}/api/example",
100
+ "json": {
101
+ "stateName": "${params.state}",
102
+ "city": "${data:cityMaster["New Delhi"].name}",
103
+ "cityRecord": "${data:cityMaster["New Delhi"]._rec}"
104
+ }
105
+ }
106
+ }
107
+ }
108
+ ]
109
+ }
110
+ ```
111
+
112
+ ## Ops Reference
113
+
114
+ ### **Op: `api.request`**
115
+ Description: Executes an HTTP request using the API adapter.
116
+
117
+ Options in `with`:
118
+ - `method` (required)
119
+ - `url` (required)
120
+ - `headers` (optional)
121
+ - `json` (optional)
122
+ - `bodyText` (optional)
123
+ - `query` (optional, object or querystring)
124
+ - `formData` (optional, array or object)
125
+ - `body` (optional alias for `formData`)
126
+
127
+ Returns:
128
+ - `status`
129
+ - `headers`
130
+ - `bodyText`
131
+ - `bodyJson` (when JSON is detected)
132
+ - `body` (alias for `bodyJson ?? bodyText`)
133
+
134
+ Notes:
135
+ - Sets `ctx.last.apiResponse` for `assert.httpStatus`.
136
+ - `formData` can be an array of items or a plain object.
137
+ - If `formData` is an object, keys become field names and values become field values.
138
+ - File values can be `file:/absolute/path` or `url:https://...` and will be uploaded as files.
139
+ - Non-string object values are JSON-stringified before sending.
140
+
141
+ Form data item notes:
142
+ - Array form items: `{ name, value, type?: "text" | "file", filename?, contentType? }`.
143
+ - File values can be `file:/absolute/path` or `url:https://...`.
144
+ - If `formData` is an object, keys become field names and values become field values.
145
+ - Use `formData`/`body` instead of `json` or `bodyText`.
146
+
147
+ Example (array form):
148
+ ```json
149
+ {
150
+ "when": {
151
+ "op": "api.request",
152
+ "with": {
153
+ "method": "POST",
154
+ "url": "${env:API_BASE_URL}/api/lead",
155
+ "formData": [
156
+ { "name": "venueUserKey", "value": "Kolhapur-Karvir" },
157
+ { "name": "coupon", "type": "file", "value": "file:/abs/path/image.jpg" },
158
+ { "name": "campaignUserKey", "value": "Campaign: Drawing Competition" }
159
+ ]
160
+ }
161
+ }
162
+ }
163
+ ```
164
+
165
+ Example (object form from `testing.data`):
166
+ ```json
167
+ {
168
+ "when": {
169
+ "op": "api.request",
170
+ "with": {
171
+ "method": "POST",
172
+ "url": "${env:API_BASE_URL}/api/lead",
173
+ "formData": "${data:lead[\"LeadWithFile\"]._rec}"
174
+ }
175
+ }
176
+ }
177
+ ```
178
+
179
+ ### **Op: `api.auth.bearerFromLogin`**
180
+ Description: Logs in and returns a bearer access token from the response.
181
+
182
+ Options in `with`:
183
+ - `url` (required)
184
+ - `username` (required)
185
+ - `password` (required)
186
+
187
+ Returns:
188
+ - access token string
189
+
190
+ ### **Op: `ui.goto`**
191
+ Description: Navigates the browser to a URL.
192
+
193
+ Options in `with`:
194
+ - `url` (required)
195
+
196
+ ### **Op: `ui.expectUrl`**
197
+ Description: Asserts the current page URL.
198
+
199
+ Options in `with`:
200
+ - `equals` (optional)
201
+ - `contains` (optional)
202
+
203
+ ### **Op: `ui.fill`**
204
+ Description: Fills an input or editable element.
205
+
206
+ Options in `with`:
207
+ - `selector` (required)
208
+ - `value` (required)
209
+
210
+ ### **Op: `ui.select`**
211
+ Description: Selects an option in a select element.
212
+
213
+ Options in `with`:
214
+ - `selector` (required)
215
+ - `value` (required)
216
+
217
+ ### **Op: `ui.click`**
218
+ Description: Clicks an element located by selector.
219
+
220
+ Options in `with`:
221
+ - `selector` (required)
222
+
223
+ ### **Op: `ui.press`**
224
+ Description: Presses a keyboard key on a focused element.
225
+
226
+ Options in `with`:
227
+ - `selector` (required)
228
+ - `key` (required)
229
+
230
+ ### **Op: `ui.expectVisible`**
231
+ Description: Waits for an element to be visible.
232
+
233
+ Options in `with`:
234
+ - `selector` (required)
235
+
236
+ ### **Op: `ui.expectText`**
237
+ Description: Asserts the text content of an element.
238
+
239
+ Options in `with`:
240
+ - `selector` (required)
241
+ - `equals` (optional)
242
+ - `contains` (optional)
243
+
244
+ ### **Op: `assert.equals`**
245
+ Description: Asserts strict equality between two values.
246
+
247
+ Options in `with`:
248
+ - `actual` (required)
249
+ - `expected` (required)
250
+
251
+ ### **Op: `assert.contains`**
252
+ Description: Asserts a string contains a substring.
253
+
254
+ Options in `with`:
255
+ - `actual` (required)
256
+ - `expected` (required)
257
+
258
+ ### **Op: `assert.matches`**
259
+ Description: Asserts a string matches a regex pattern.
260
+
261
+ Options in `with`:
262
+ - `actual` (required)
263
+ - `pattern` (required)
264
+
265
+ ### **Op: `assert.httpStatus`**
266
+ Description: Asserts the HTTP status of the last API response (or a provided response).
267
+
268
+ Options in `with`:
269
+ - `is` (required)
270
+ - `from` (optional, defaults to `ctx.last.apiResponse`)
271
+
272
+ ### **Op: `assert.jsonPath`**
273
+ Description: Asserts a JSONPath-resolved value equals an expected value.
274
+
275
+ Options in `with`:
276
+ - `from` (required)
277
+ - `path` (required)
278
+ - `equals` (required)
279
+
280
+ ### **Op: `util.log`**
281
+ Description: Logs a message (and optional data) to the console.
282
+
283
+ Options in `with`:
284
+ - `message` (required)
285
+ - `data` (optional)
286
+
287
+ ### **Op: `util.sleep`**
288
+ Description: Pauses execution for a fixed duration.
289
+
290
+ Options in `with`:
291
+ - `ms` (required)
292
+
293
+ ### **Op: `util.require`**
294
+ Description: Fails the step if a required resource is missing.
295
+
296
+ Options in `with`:
297
+ - `resource` (required)
298
+ - `message` (optional)
299
+
300
+ ### **Op: `test.spec`**
301
+ Description: Runs a custom test spec registered via testing.specs.
302
+
303
+ Options in `with`:
304
+ - `input` (optional, free-form object passed to the spec)
305
+ - `specId` (optional alternative to `step.spec`)
306
+
307
+ Step fields:
308
+ - `spec` (required unless `with.specId` is provided)
309
+
310
+ Returns:
311
+ - `SolidTestSpecResult` (saved if `saveAs` is provided)
312
+
313
+ ## Custom Specs (test.spec)
314
+ Purpose: escape hatch for fully custom test logic.
315
+
316
+ Step shape example:
317
+ ```json
318
+ {
319
+ "when": {
320
+ "op": "test.spec",
321
+ "spec": "example.customHealth",
322
+ "with": { "input": { "url": "${env:API_BASE_URL}/health" } },
323
+ "saveAs": "custom.health"
324
+ }
325
+ }
326
+ ```
327
+
328
+ Register specs in the consuming project:
329
+ ```ts
330
+ import { runFromMetadata } from "./runner/run-from-metadata";
331
+
332
+ await runFromMetadata({
333
+ // ...
334
+ specs: (specRegistry) => {
335
+ specRegistry.register("example.customHealth", () => new CustomHealthSpec());
336
+ }
337
+ });
338
+ ```
339
+
340
+ When using `solidctl test run`, specs are loaded from `testing.specs` in module metadata.
341
+ Use `--skip-scenario-ids` to exclude scenarios by id (comma-separated).
342
+ Use `--print-api-logs` to print full API request/response details for `api.request` steps.
343
+ Use `--print-api-logs` to print full API request/response details for `api.request` steps.
344
+
345
+ ## Run From Metadata
346
+ ```ts
347
+ import { runFromMetadata } from "./runner/run-from-metadata";
348
+ import metadata from "./testing-metadata.json";
349
+
350
+ await runFromMetadata({
351
+ metadata,
352
+ includeTags: ["smoke"],
353
+ defaults: { timeoutMs: 30_000, retries: 1 },
354
+ api: { baseUrl: "https://api.example.com" },
355
+ ui: { baseUrl: "https://app.example.com", headless: true }
356
+ });
357
+ ```
358
+
359
+ ## Add A New Step (SOP)
360
+ 1. Create a new `*.step.ts` in the right domain folder.
361
+ 2. Implement a `registerXSteps(registry)` function and `registry.register("op.name", handler)`.
362
+ 3. Validate required `step.with` fields and throw clear errors.
363
+ 4. Use adapters via `ctx.api` / `ctx.ui` and update `ctx.last` when helpful.
364
+ 5. Export and register it from the domain `index.ts`.
@@ -0,0 +1,6 @@
1
+ import { SpecRegistry } from "../core/spec-registry";
2
+ import { CustomHealthSpec } from "./specs/custom-health.spec";
3
+
4
+ export function registerExampleSpecs(specRegistry: SpecRegistry): void {
5
+ specRegistry.register("example.customHealth", () => new CustomHealthSpec());
6
+ }
@@ -0,0 +1,29 @@
1
+ import type { ISolidTestSpec, SolidTestSpecArgs } from "../../contracts/test-spec.types";
2
+
3
+ export class CustomHealthSpec implements ISolidTestSpec {
4
+ async run({ ctx, input }: SolidTestSpecArgs) {
5
+ if (!ctx.api) {
6
+ throw new Error("Missing API adapter on context for CustomHealthSpec");
7
+ }
8
+ const url = input?.url as string | undefined;
9
+ if (!url) {
10
+ throw new Error('Missing "url" in input for CustomHealthSpec');
11
+ }
12
+
13
+ const response = await ctx.api.http({ method: "GET", url });
14
+
15
+ return {
16
+ ok: response.status === 200,
17
+ name: "Custom API health spec",
18
+ details: { status: response.status },
19
+ attachments: [
20
+ {
21
+ name: "health-response",
22
+ contentType: "application/json",
23
+ data: JSON.stringify(response, null, 2),
24
+ encoding: "utf8" as const,
25
+ },
26
+ ],
27
+ };
28
+ }
29
+ }
@@ -0,0 +1,82 @@
1
+ {
2
+ "testing": {
3
+ "scenarios": [
4
+ {
5
+ "id": "api-health",
6
+ "name": "API health check",
7
+ "type": "api",
8
+ "steps": [
9
+ {
10
+ "given": {
11
+ "op": "api.request",
12
+ "with": {
13
+ "method": "GET",
14
+ "url": "${env:API_BASE_URL}/health"
15
+ },
16
+ "saveAs": "lastHealth"
17
+ }
18
+ },
19
+ {
20
+ "then": {
21
+ "op": "assert.httpStatus",
22
+ "with": {
23
+ "is": 200
24
+ }
25
+ }
26
+ }
27
+ ]
28
+ },
29
+ {
30
+ "id": "ui-home",
31
+ "name": "UI home page",
32
+ "type": "ui",
33
+ "steps": [
34
+ {
35
+ "given": {
36
+ "op": "ui.goto",
37
+ "with": {
38
+ "url": "${env:UI_BASE_URL}/"
39
+ }
40
+ }
41
+ },
42
+ {
43
+ "then": {
44
+ "op": "ui.expectUrl",
45
+ "with": {
46
+ "contains": "/"
47
+ }
48
+ }
49
+ }
50
+ ]
51
+ },
52
+ {
53
+ "id": "custom-spec-health",
54
+ "name": "Custom spec health check",
55
+ "type": "api",
56
+ "steps": [
57
+ {
58
+ "when": {
59
+ "op": "test.spec",
60
+ "spec": "example.customHealth",
61
+ "with": {
62
+ "input": {
63
+ "url": "${env:API_BASE_URL}/health"
64
+ }
65
+ },
66
+ "saveAs": "customHealthResult"
67
+ }
68
+ },
69
+ {
70
+ "then": {
71
+ "op": "assert.equals",
72
+ "with": {
73
+ "actual": "${res:customHealthResult.ok}",
74
+ "expected": "true"
75
+ }
76
+ }
77
+ }
78
+ ]
79
+ }
80
+ ]
81
+ }
82
+ }
@@ -0,0 +1,85 @@
1
+ import axios from "axios";
2
+
3
+ import type { ApiResponse } from "../../contracts/runtime-context.types";
4
+ import type { ApiAdapterOptions, ApiRequestOptions } from "./api.types";
5
+
6
+ function hasHeader(headers: Record<string, string>, name: string): boolean {
7
+ return Object.prototype.hasOwnProperty.call(headers, name.toLowerCase());
8
+ }
9
+
10
+ export class ApiAdapter {
11
+ private readonly baseUrl?: string;
12
+ private readonly defaultHeaders?: Record<string, string>;
13
+
14
+ constructor(opts?: ApiAdapterOptions) {
15
+ this.baseUrl = opts?.baseUrl;
16
+ this.defaultHeaders = opts?.defaultHeaders;
17
+ }
18
+
19
+ async http(req: ApiRequestOptions): Promise<ApiResponse> {
20
+ const headers: Record<string, string> = {
21
+ ...(this.defaultHeaders ?? {}),
22
+ ...(req.headers ?? {}),
23
+ };
24
+
25
+ if (req.formData) {
26
+ const formHeaders = req.formData.getHeaders();
27
+ for (const [key, value] of Object.entries(formHeaders)) {
28
+ headers[key.toLowerCase()] = String(value);
29
+ }
30
+ } else if (req.json !== undefined && !hasHeader(headers, "content-type")) {
31
+ headers["content-type"] = "application/json";
32
+ }
33
+
34
+ const response = await axios.request({
35
+ baseURL: this.baseUrl,
36
+ url: req.url,
37
+ method: req.method as any,
38
+ headers,
39
+ data: req.formData ?? (req.json !== undefined ? req.json : req.bodyText),
40
+ responseType: "text",
41
+ transformResponse: (data) => data,
42
+ validateStatus: () => true,
43
+ });
44
+
45
+ const bodyText = typeof response.data === "string"
46
+ ? response.data
47
+ : String(response.data);
48
+ const responseHeaders = Object.fromEntries(
49
+ Object.entries(response.headers ?? {}).map(([key, value]) => [
50
+ key.toLowerCase(),
51
+ Array.isArray(value) ? value.join(", ") : String(value),
52
+ ]),
53
+ ) as Record<string, string>;
54
+
55
+ let bodyJson: unknown;
56
+ const contentType = responseHeaders["content-type"] ?? "";
57
+ if (contentType.toLowerCase().includes("application/json")) {
58
+ try {
59
+ bodyJson = JSON.parse(bodyText);
60
+ } catch {
61
+ // ignore parse errors
62
+ }
63
+ }
64
+
65
+ if (bodyJson === undefined) {
66
+ const trimmed = bodyText.trim();
67
+ if (trimmed.startsWith("{") || trimmed.startsWith("[")) {
68
+ try {
69
+ bodyJson = JSON.parse(trimmed);
70
+ } catch {
71
+ // ignore parse errors
72
+ }
73
+ }
74
+ }
75
+
76
+ const apiResponse: ApiResponse = {
77
+ status: response.status,
78
+ headers: responseHeaders,
79
+ bodyText,
80
+ ...(bodyJson !== undefined ? { bodyJson } : {}),
81
+ };
82
+
83
+ return apiResponse;
84
+ }
85
+ }
@@ -0,0 +1,15 @@
1
+ import type FormData from "form-data";
2
+
3
+ export interface ApiAdapterOptions {
4
+ baseUrl?: string;
5
+ defaultHeaders?: Record<string, string>;
6
+ }
7
+
8
+ export interface ApiRequestOptions {
9
+ method: string;
10
+ url: string;
11
+ headers?: Record<string, string>;
12
+ json?: unknown;
13
+ bodyText?: string;
14
+ formData?: FormData;
15
+ }
@@ -0,0 +1,54 @@
1
+ import type { Browser, BrowserContext, Page } from "playwright";
2
+
3
+ import type { PlaywrightAdapterOptions } from "./ui.types";
4
+
5
+ function isAbsoluteUrl(url: string): boolean {
6
+ return /^https?:\/\//i.test(url);
7
+ }
8
+
9
+ export class PlaywrightAdapter {
10
+ private readonly baseUrl?: string;
11
+ private readonly headless: boolean;
12
+ private browser?: Browser;
13
+ private context?: BrowserContext;
14
+ public page?: Page;
15
+
16
+ constructor(opts?: PlaywrightAdapterOptions) {
17
+ this.baseUrl = opts?.baseUrl;
18
+ this.headless = opts?.headless ?? true;
19
+ }
20
+
21
+ async start(): Promise<void> {
22
+ const { chromium } = await import('playwright');
23
+ this.browser = await chromium.launch({ headless: this.headless });
24
+ this.context = await this.browser.newContext();
25
+ this.page = await this.context.newPage();
26
+ }
27
+
28
+ async stop(): Promise<void> {
29
+ try {
30
+ if (this.context) {
31
+ await this.context.close();
32
+ }
33
+ } finally {
34
+ this.context = undefined;
35
+ this.page = undefined;
36
+ }
37
+
38
+ try {
39
+ if (this.browser) {
40
+ await this.browser.close();
41
+ }
42
+ } finally {
43
+ this.browser = undefined;
44
+ }
45
+ }
46
+
47
+ resolveUrl(url: string): string {
48
+ if (isAbsoluteUrl(url)) return url;
49
+ if (this.baseUrl) {
50
+ return new URL(url, this.baseUrl).toString();
51
+ }
52
+ return url;
53
+ }
54
+ }
@@ -0,0 +1,4 @@
1
+ export interface PlaywrightAdapterOptions {
2
+ headless?: boolean;
3
+ baseUrl?: string;
4
+ }
@@ -0,0 +1,36 @@
1
+ import type { ApiAdapter } from "../adapters/api/api-adapter";
2
+ import type { PlaywrightAdapter } from "../adapters/ui/playwright-adapter";
3
+ import type { Reporter } from "../reporter/reporter.types";
4
+ import type { SpecRegistry } from "../core/spec-registry";
5
+ import type { ScenarioType } from "./testing-metadata.types";
6
+
7
+ export type StepPhase = "given" | "when" | "then" | "and" | "step";
8
+
9
+ export interface ResourceStore {
10
+ get(path: string): unknown;
11
+ set(path: string, value: unknown): void;
12
+ has(path: string): boolean;
13
+ }
14
+
15
+ export interface ApiResponse {
16
+ status: number;
17
+ headers: Record<string, string>;
18
+ bodyText: string;
19
+ bodyJson?: unknown;
20
+ }
21
+
22
+ export interface TestContext {
23
+ scenarioId: string;
24
+ scenarioType: ScenarioType;
25
+ params: Record<string, any>;
26
+ resources: ResourceStore;
27
+ api?: ApiAdapter;
28
+ ui?: PlaywrightAdapter;
29
+ last?: { apiResponse?: ApiResponse };
30
+ reporter: Reporter;
31
+ specRegistry?: SpecRegistry;
32
+ testData?: Record<string, Record<string, any>>;
33
+ options?: {
34
+ printApiLogs?: boolean;
35
+ };
36
+ }
@@ -0,0 +1,24 @@
1
+ import type { TestContext } from "../contracts/runtime-context.types";
2
+
3
+ export type SolidTestSpecArgs = {
4
+ ctx: TestContext;
5
+ input: Record<string, any>;
6
+ };
7
+
8
+ export type SolidTestSpecAttachment = {
9
+ name: string;
10
+ contentType: string;
11
+ data: string;
12
+ encoding?: "utf8" | "base64";
13
+ };
14
+
15
+ export type SolidTestSpecResult = {
16
+ ok: boolean;
17
+ name?: string;
18
+ details?: Record<string, any>;
19
+ attachments?: SolidTestSpecAttachment[];
20
+ };
21
+
22
+ export interface ISolidTestSpec {
23
+ run(args: SolidTestSpecArgs): Promise<SolidTestSpecResult>;
24
+ }