@thinkwise/testwise 0.2.67 → 0.2.103

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 (434) hide show
  1. package/Testwise.ts +35 -0
  2. package/artifact-builder/ArtifactManager.ts +25 -2
  3. package/artifact-builder/ComponentClassModelBuilder.ts +148 -0
  4. package/artifact-builder/InterfaceGenerator.ts +31 -33
  5. package/artifact-builder/ModelDataBuilder.ts +18 -20
  6. package/artifact-builder/ModelDataRefiner.ts +23 -3
  7. package/artifact-builder/SchemaGenerator.ts +45 -35
  8. package/artifact-builder/ScreenInterfaceRefiner.ts +25 -10
  9. package/artifact-builder/SelectorBuilder.ts +30 -24
  10. package/artifact-builder/SubjectClassModelBuilder.ts +209 -0
  11. package/artifact-builder/SubjectComponentGenerator.ts +67 -246
  12. package/artifact-builder/SubjectGenerator.ts +117 -230
  13. package/artifact-builder/SubjectRegistration.ts +41 -32
  14. package/artifact-builder/TsFileModel.ts +94 -0
  15. package/artifact-builder/TsFileSerializer.ts +247 -0
  16. package/artifact-builder/helpers/DataRetriever.ts +64 -27
  17. package/artifact-builder/helpers/NamingHandler.ts +23 -78
  18. package/artifact-builder/helpers/PipelinePaths.ts +123 -0
  19. package/artifact-builder/helpers/Stopwatch.ts +10 -0
  20. package/artifact-builder/helpers/index.ts +1 -0
  21. package/artifact-builder/index.ts +4 -0
  22. package/components/BaseComponentObjects.ts +17 -0
  23. package/components/action-bar/ActionBar.ts +35 -47
  24. package/components/action-bar/ActionBarObjects.ts +2 -0
  25. package/components/action-bar/CustomActionBar.ts +6 -0
  26. package/components/cardlist/Cardlist.ts +6 -0
  27. package/components/chart/Chart.ts +6 -0
  28. package/components/combined-filter/CombinedFilter.ts +9 -0
  29. package/components/cube-view-bar/CubeViewBar.ts +6 -0
  30. package/components/export/ExportComponent.ts +12 -0
  31. package/components/filter/ExcelStyleFilterPopup.ts +35 -2
  32. package/components/filter/FilterForm.ts +10 -0
  33. package/components/filter/FilterPopup.ts +30 -9
  34. package/components/filter/FilterPopupObjects.ts +10 -3
  35. package/components/filter/FindForm.ts +7 -0
  36. package/components/filter/ManagePrefilterPopup.ts +11 -0
  37. package/components/form/Form.ts +16 -0
  38. package/components/grid/Grid.ts +18 -1
  39. package/components/maps/Maps.ts +6 -0
  40. package/components/menu/ListBarMenuComponent.ts +10 -0
  41. package/components/pivot-grid/PivotGrid.ts +6 -0
  42. package/components/pivot-grid/PivotGridFieldList.ts +7 -0
  43. package/components/pop-up/AllRowsPopUp.ts +12 -0
  44. package/components/pop-up/PopUpComponent.ts +11 -0
  45. package/components/prefilter-list/PrefilterList.ts +9 -0
  46. package/components/preview/Preview.ts +6 -0
  47. package/components/report-bar/ReportBar.ts +6 -0
  48. package/components/report-tiles/ReportTiles.ts +6 -0
  49. package/components/scheduler/Scheduler.ts +6 -0
  50. package/components/snackbar/SnackBar.ts +12 -0
  51. package/components/splitter/Splitter.ts +6 -0
  52. package/components/tab/BaseTab.ts +5 -0
  53. package/components/tab/DetailTabPage.ts +11 -0
  54. package/components/tab/Tab.ts +10 -0
  55. package/components/task/TaskBar.ts +13 -3
  56. package/components/task/TaskTiles.ts +12 -3
  57. package/components/topbar/TopBar.ts +10 -0
  58. package/components/tree-view/TreeView.ts +9 -0
  59. package/controls/DateControl.ts +40 -1
  60. package/controls/FormComboBox.ts +30 -0
  61. package/controls/GridColumnControl.ts +34 -3
  62. package/controls/InputFieldControl.ts +49 -0
  63. package/controls/LookupDropdown.ts +29 -0
  64. package/dist/Testwise.js +35 -0
  65. package/dist/Testwise.js.map +1 -1
  66. package/dist/artifact-builder/ArtifactManager.d.ts +18 -1
  67. package/dist/artifact-builder/ArtifactManager.js +24 -2
  68. package/dist/artifact-builder/ArtifactManager.js.map +1 -1
  69. package/dist/artifact-builder/ComponentClassModelBuilder.d.ts +22 -0
  70. package/dist/artifact-builder/ComponentClassModelBuilder.js +115 -0
  71. package/dist/artifact-builder/ComponentClassModelBuilder.js.map +1 -0
  72. package/dist/artifact-builder/InterfaceGenerator.d.ts +15 -6
  73. package/dist/artifact-builder/InterfaceGenerator.js +27 -26
  74. package/dist/artifact-builder/InterfaceGenerator.js.map +1 -1
  75. package/dist/artifact-builder/ModelDataBuilder.d.ts +7 -0
  76. package/dist/artifact-builder/ModelDataBuilder.js +13 -5
  77. package/dist/artifact-builder/ModelDataBuilder.js.map +1 -1
  78. package/dist/artifact-builder/ModelDataRefiner.d.ts +18 -1
  79. package/dist/artifact-builder/ModelDataRefiner.js +18 -3
  80. package/dist/artifact-builder/ModelDataRefiner.js.map +1 -1
  81. package/dist/artifact-builder/SchemaGenerator.d.ts +21 -5
  82. package/dist/artifact-builder/SchemaGenerator.js +38 -26
  83. package/dist/artifact-builder/SchemaGenerator.js.map +1 -1
  84. package/dist/artifact-builder/ScreenInterfaceRefiner.d.ts +18 -1
  85. package/dist/artifact-builder/ScreenInterfaceRefiner.js +23 -9
  86. package/dist/artifact-builder/ScreenInterfaceRefiner.js.map +1 -1
  87. package/dist/artifact-builder/SelectorBuilder.d.ts +18 -5
  88. package/dist/artifact-builder/SelectorBuilder.js +29 -14
  89. package/dist/artifact-builder/SelectorBuilder.js.map +1 -1
  90. package/dist/artifact-builder/SubjectClassModelBuilder.d.ts +38 -0
  91. package/dist/artifact-builder/SubjectClassModelBuilder.js +158 -0
  92. package/dist/artifact-builder/SubjectClassModelBuilder.js.map +1 -0
  93. package/dist/artifact-builder/SubjectComponentGenerator.d.ts +25 -14
  94. package/dist/artifact-builder/SubjectComponentGenerator.js +65 -189
  95. package/dist/artifact-builder/SubjectComponentGenerator.js.map +1 -1
  96. package/dist/artifact-builder/SubjectGenerator.d.ts +32 -13
  97. package/dist/artifact-builder/SubjectGenerator.js +81 -165
  98. package/dist/artifact-builder/SubjectGenerator.js.map +1 -1
  99. package/dist/artifact-builder/SubjectRegistration.d.ts +22 -8
  100. package/dist/artifact-builder/SubjectRegistration.js +29 -14
  101. package/dist/artifact-builder/SubjectRegistration.js.map +1 -1
  102. package/dist/artifact-builder/TsFileModel.d.ts +86 -0
  103. package/dist/artifact-builder/TsFileModel.js +2 -0
  104. package/dist/artifact-builder/TsFileModel.js.map +1 -0
  105. package/dist/artifact-builder/TsFileSerializer.d.ts +19 -0
  106. package/dist/artifact-builder/TsFileSerializer.js +225 -0
  107. package/dist/artifact-builder/TsFileSerializer.js.map +1 -0
  108. package/dist/artifact-builder/helpers/DataRetriever.d.ts +22 -3
  109. package/dist/artifact-builder/helpers/DataRetriever.js +56 -26
  110. package/dist/artifact-builder/helpers/DataRetriever.js.map +1 -1
  111. package/dist/artifact-builder/helpers/NamingHandler.d.ts +18 -6
  112. package/dist/artifact-builder/helpers/NamingHandler.js +20 -61
  113. package/dist/artifact-builder/helpers/NamingHandler.js.map +1 -1
  114. package/dist/artifact-builder/helpers/PipelinePaths.d.ts +52 -0
  115. package/dist/artifact-builder/helpers/PipelinePaths.js +99 -0
  116. package/dist/artifact-builder/helpers/PipelinePaths.js.map +1 -0
  117. package/dist/artifact-builder/helpers/Stopwatch.d.ts +10 -0
  118. package/dist/artifact-builder/helpers/Stopwatch.js +10 -0
  119. package/dist/artifact-builder/helpers/Stopwatch.js.map +1 -1
  120. package/dist/artifact-builder/helpers/index.d.ts +1 -0
  121. package/dist/artifact-builder/helpers/index.js +1 -0
  122. package/dist/artifact-builder/helpers/index.js.map +1 -1
  123. package/dist/artifact-builder/index.d.ts +4 -0
  124. package/dist/artifact-builder/index.js +4 -0
  125. package/dist/artifact-builder/index.js.map +1 -1
  126. package/dist/components/BaseComponentObjects.d.ts +17 -0
  127. package/dist/components/BaseComponentObjects.js +17 -0
  128. package/dist/components/BaseComponentObjects.js.map +1 -1
  129. package/dist/components/action-bar/ActionBar.d.ts +21 -24
  130. package/dist/components/action-bar/ActionBar.js +31 -24
  131. package/dist/components/action-bar/ActionBar.js.map +1 -1
  132. package/dist/components/action-bar/ActionBarObjects.d.ts +1 -0
  133. package/dist/components/action-bar/ActionBarObjects.js +1 -0
  134. package/dist/components/action-bar/ActionBarObjects.js.map +1 -1
  135. package/dist/components/action-bar/CustomActionBar.d.ts +6 -0
  136. package/dist/components/action-bar/CustomActionBar.js +6 -0
  137. package/dist/components/action-bar/CustomActionBar.js.map +1 -1
  138. package/dist/components/cardlist/Cardlist.d.ts +6 -0
  139. package/dist/components/cardlist/Cardlist.js +6 -0
  140. package/dist/components/cardlist/Cardlist.js.map +1 -1
  141. package/dist/components/chart/Chart.d.ts +6 -0
  142. package/dist/components/chart/Chart.js +6 -0
  143. package/dist/components/chart/Chart.js.map +1 -1
  144. package/dist/components/combined-filter/CombinedFilter.d.ts +9 -0
  145. package/dist/components/combined-filter/CombinedFilter.js +9 -0
  146. package/dist/components/combined-filter/CombinedFilter.js.map +1 -1
  147. package/dist/components/cube-view-bar/CubeViewBar.d.ts +6 -0
  148. package/dist/components/cube-view-bar/CubeViewBar.js +6 -0
  149. package/dist/components/cube-view-bar/CubeViewBar.js.map +1 -1
  150. package/dist/components/export/ExportComponent.d.ts +12 -0
  151. package/dist/components/export/ExportComponent.js +12 -0
  152. package/dist/components/export/ExportComponent.js.map +1 -1
  153. package/dist/components/filter/ExcelStyleFilterPopup.d.ts +17 -4
  154. package/dist/components/filter/ExcelStyleFilterPopup.js +35 -23
  155. package/dist/components/filter/ExcelStyleFilterPopup.js.map +1 -1
  156. package/dist/components/filter/ExcelStyleFilterPopupObjects.d.ts +1 -1
  157. package/dist/components/filter/ExcelStyleFilterPopupObjects.js +2 -2
  158. package/dist/components/filter/ExcelStyleFilterPopupObjects.js.map +1 -1
  159. package/dist/components/filter/FilterForm.d.ts +10 -0
  160. package/dist/components/filter/FilterForm.js +10 -0
  161. package/dist/components/filter/FilterForm.js.map +1 -1
  162. package/dist/components/filter/FilterPopup.d.ts +22 -4
  163. package/dist/components/filter/FilterPopup.js +17 -9
  164. package/dist/components/filter/FilterPopup.js.map +1 -1
  165. package/dist/components/filter/FilterPopupObjects.d.ts +5 -2
  166. package/dist/components/filter/FilterPopupObjects.js +5 -2
  167. package/dist/components/filter/FilterPopupObjects.js.map +1 -1
  168. package/dist/components/filter/FindForm.d.ts +7 -0
  169. package/dist/components/filter/FindForm.js +7 -0
  170. package/dist/components/filter/FindForm.js.map +1 -1
  171. package/dist/components/filter/ManagePrefilterPopup.d.ts +11 -0
  172. package/dist/components/filter/ManagePrefilterPopup.js +11 -0
  173. package/dist/components/filter/ManagePrefilterPopup.js.map +1 -1
  174. package/dist/components/form/Form.d.ts +16 -0
  175. package/dist/components/form/Form.js +16 -0
  176. package/dist/components/form/Form.js.map +1 -1
  177. package/dist/components/grid/Grid.d.ts +17 -0
  178. package/dist/components/grid/Grid.js +18 -1
  179. package/dist/components/grid/Grid.js.map +1 -1
  180. package/dist/components/maps/Maps.d.ts +6 -0
  181. package/dist/components/maps/Maps.js +6 -0
  182. package/dist/components/maps/Maps.js.map +1 -1
  183. package/dist/components/menu/ListBarMenuComponent.d.ts +10 -0
  184. package/dist/components/menu/ListBarMenuComponent.js +10 -0
  185. package/dist/components/menu/ListBarMenuComponent.js.map +1 -1
  186. package/dist/components/pivot-grid/PivotGrid.d.ts +6 -0
  187. package/dist/components/pivot-grid/PivotGrid.js +6 -0
  188. package/dist/components/pivot-grid/PivotGrid.js.map +1 -1
  189. package/dist/components/pivot-grid/PivotGridFieldList.d.ts +7 -0
  190. package/dist/components/pivot-grid/PivotGridFieldList.js +7 -0
  191. package/dist/components/pivot-grid/PivotGridFieldList.js.map +1 -1
  192. package/dist/components/pop-up/AllRowsPopUp.d.ts +12 -0
  193. package/dist/components/pop-up/AllRowsPopUp.js +12 -0
  194. package/dist/components/pop-up/AllRowsPopUp.js.map +1 -1
  195. package/dist/components/pop-up/PopUpComponent.d.ts +11 -0
  196. package/dist/components/pop-up/PopUpComponent.js +11 -0
  197. package/dist/components/pop-up/PopUpComponent.js.map +1 -1
  198. package/dist/components/prefilter-list/PrefilterList.d.ts +9 -0
  199. package/dist/components/prefilter-list/PrefilterList.js +9 -0
  200. package/dist/components/prefilter-list/PrefilterList.js.map +1 -1
  201. package/dist/components/preview/Preview.d.ts +6 -0
  202. package/dist/components/preview/Preview.js +6 -0
  203. package/dist/components/preview/Preview.js.map +1 -1
  204. package/dist/components/report-bar/ReportBar.d.ts +6 -0
  205. package/dist/components/report-bar/ReportBar.js +6 -0
  206. package/dist/components/report-bar/ReportBar.js.map +1 -1
  207. package/dist/components/report-tiles/ReportTiles.d.ts +6 -0
  208. package/dist/components/report-tiles/ReportTiles.js +6 -0
  209. package/dist/components/report-tiles/ReportTiles.js.map +1 -1
  210. package/dist/components/scheduler/Scheduler.d.ts +6 -0
  211. package/dist/components/scheduler/Scheduler.js +6 -0
  212. package/dist/components/scheduler/Scheduler.js.map +1 -1
  213. package/dist/components/snackbar/SnackBar.d.ts +12 -0
  214. package/dist/components/snackbar/SnackBar.js +12 -0
  215. package/dist/components/snackbar/SnackBar.js.map +1 -1
  216. package/dist/components/splitter/Splitter.d.ts +6 -0
  217. package/dist/components/splitter/Splitter.js +6 -0
  218. package/dist/components/splitter/Splitter.js.map +1 -1
  219. package/dist/components/tab/BaseTab.d.ts +5 -0
  220. package/dist/components/tab/BaseTab.js +5 -0
  221. package/dist/components/tab/BaseTab.js.map +1 -1
  222. package/dist/components/tab/DetailTabPage.d.ts +11 -0
  223. package/dist/components/tab/DetailTabPage.js +11 -0
  224. package/dist/components/tab/DetailTabPage.js.map +1 -1
  225. package/dist/components/tab/Tab.d.ts +10 -0
  226. package/dist/components/tab/Tab.js +10 -0
  227. package/dist/components/tab/Tab.js.map +1 -1
  228. package/dist/components/task/TaskBar.d.ts +12 -2
  229. package/dist/components/task/TaskBar.js +13 -3
  230. package/dist/components/task/TaskBar.js.map +1 -1
  231. package/dist/components/task/TaskTiles.d.ts +11 -2
  232. package/dist/components/task/TaskTiles.js +12 -3
  233. package/dist/components/task/TaskTiles.js.map +1 -1
  234. package/dist/components/topbar/TopBar.d.ts +10 -0
  235. package/dist/components/topbar/TopBar.js +10 -0
  236. package/dist/components/topbar/TopBar.js.map +1 -1
  237. package/dist/components/tree-view/TreeView.d.ts +9 -0
  238. package/dist/components/tree-view/TreeView.js +9 -0
  239. package/dist/components/tree-view/TreeView.js.map +1 -1
  240. package/dist/controls/DateControl.d.ts +39 -0
  241. package/dist/controls/DateControl.js +18 -1
  242. package/dist/controls/DateControl.js.map +1 -1
  243. package/dist/controls/FormComboBox.d.ts +30 -0
  244. package/dist/controls/FormComboBox.js +8 -0
  245. package/dist/controls/FormComboBox.js.map +1 -1
  246. package/dist/controls/GridColumnControl.d.ts +30 -0
  247. package/dist/controls/GridColumnControl.js +12 -3
  248. package/dist/controls/GridColumnControl.js.map +1 -1
  249. package/dist/controls/InputFieldControl.d.ts +49 -0
  250. package/dist/controls/InputFieldControl.js +30 -0
  251. package/dist/controls/InputFieldControl.js.map +1 -1
  252. package/dist/controls/LookupDropdown.d.ts +29 -0
  253. package/dist/controls/LookupDropdown.js +8 -0
  254. package/dist/controls/LookupDropdown.js.map +1 -1
  255. package/dist/enums/ElementTypes.d.ts +18 -0
  256. package/dist/enums/ElementTypes.js +18 -0
  257. package/dist/enums/ElementTypes.js.map +1 -1
  258. package/dist/enums/ExportFormat.d.ts +8 -0
  259. package/dist/enums/ExportFormat.js +8 -0
  260. package/dist/enums/ExportFormat.js.map +1 -1
  261. package/dist/enums/LogLevel.d.ts +17 -0
  262. package/dist/enums/LogLevel.js +17 -1
  263. package/dist/enums/LogLevel.js.map +1 -1
  264. package/dist/enums/index.d.ts +1 -0
  265. package/dist/enums/index.js +1 -0
  266. package/dist/enums/index.js.map +1 -1
  267. package/dist/helpers/ConfigChecker.d.ts +13 -0
  268. package/dist/helpers/ConfigChecker.js +13 -0
  269. package/dist/helpers/ConfigChecker.js.map +1 -1
  270. package/dist/helpers/Ensure.d.ts +13 -0
  271. package/dist/helpers/Ensure.js +13 -0
  272. package/dist/helpers/Ensure.js.map +1 -1
  273. package/dist/helpers/FlightTracker.d.ts +13 -3
  274. package/dist/helpers/FlightTracker.js +103 -17
  275. package/dist/helpers/FlightTracker.js.map +1 -1
  276. package/dist/helpers/GlobalWaitEventHandler.d.ts +13 -0
  277. package/dist/helpers/GlobalWaitEventHandler.js +13 -0
  278. package/dist/helpers/GlobalWaitEventHandler.js.map +1 -1
  279. package/dist/helpers/LoginHelper.d.ts +35 -1
  280. package/dist/helpers/LoginHelper.js +46 -11
  281. package/dist/helpers/LoginHelper.js.map +1 -1
  282. package/dist/helpers/PathResolver.d.ts +22 -0
  283. package/dist/helpers/PathResolver.js +22 -0
  284. package/dist/helpers/PathResolver.js.map +1 -1
  285. package/dist/helpers/Poll.d.ts +13 -1
  286. package/dist/helpers/Poll.js +12 -0
  287. package/dist/helpers/Poll.js.map +1 -1
  288. package/dist/helpers/RegexHelper.d.ts +15 -0
  289. package/dist/helpers/RegexHelper.js +15 -3
  290. package/dist/helpers/RegexHelper.js.map +1 -1
  291. package/dist/helpers/SubjectNavigator.d.ts +26 -0
  292. package/dist/helpers/SubjectNavigator.js +51 -0
  293. package/dist/helpers/SubjectNavigator.js.map +1 -0
  294. package/dist/helpers/UserSimulationHelper.d.ts +14 -0
  295. package/dist/helpers/UserSimulationHelper.js +14 -0
  296. package/dist/helpers/UserSimulationHelper.js.map +1 -1
  297. package/dist/helpers/index.d.ts +1 -0
  298. package/dist/helpers/index.js +1 -0
  299. package/dist/helpers/index.js.map +1 -1
  300. package/dist/index.d.ts +6 -20
  301. package/dist/index.js +1 -0
  302. package/dist/index.js.map +1 -1
  303. package/dist/interfaces/IComponentObjects.d.ts +12 -0
  304. package/dist/interfaces/IComponentSchemaMeta.d.ts +15 -0
  305. package/dist/interfaces/IComponentSchemaMeta.js +2 -0
  306. package/dist/interfaces/IComponentSchemaMeta.js.map +1 -0
  307. package/dist/interfaces/IProperty.d.ts +13 -0
  308. package/dist/interfaces/IRegisteredSubjects.d.ts +12 -0
  309. package/dist/interfaces/ISeedSubjectDraft.d.ts +16 -0
  310. package/dist/interfaces/ISeedSubjectDraft.js +2 -0
  311. package/dist/interfaces/ISeedSubjectDraft.js.map +1 -0
  312. package/dist/interfaces/ISubject.d.ts +13 -0
  313. package/dist/interfaces/ISubjectDetail.d.ts +11 -0
  314. package/dist/interfaces/ISubjectDetail.js +2 -0
  315. package/dist/interfaces/ISubjectDetail.js.map +1 -0
  316. package/dist/mcp/ArtifactResolver.d.ts +152 -0
  317. package/dist/mcp/ArtifactResolver.js +232 -0
  318. package/dist/mcp/ArtifactResolver.js.map +1 -0
  319. package/dist/mcp/index.d.ts +2 -0
  320. package/dist/mcp/index.js +2 -0
  321. package/dist/mcp/index.js.map +1 -0
  322. package/dist/page-extensions/GlobalComponents.d.ts +30 -0
  323. package/dist/page-extensions/GlobalComponents.js +30 -0
  324. package/dist/page-extensions/GlobalComponents.js.map +1 -1
  325. package/dist/page-extensions/GoToDeepLink.d.ts +9 -0
  326. package/dist/page-extensions/GoToDeepLink.js +9 -0
  327. package/dist/page-extensions/GoToDeepLink.js.map +1 -1
  328. package/dist/page-extensions/LoginFeatures.d.ts +8 -0
  329. package/dist/page-extensions/LoginFeatures.js +8 -0
  330. package/dist/page-extensions/LoginFeatures.js.map +1 -1
  331. package/dist/page-extensions/SubjectRegistry.d.ts +31 -0
  332. package/dist/page-extensions/SubjectRegistry.js +31 -0
  333. package/dist/page-extensions/SubjectRegistry.js.map +1 -1
  334. package/dist/page-extensions/UserSimulation.d.ts +21 -0
  335. package/dist/page-extensions/UserSimulation.js +21 -0
  336. package/dist/page-extensions/UserSimulation.js.map +1 -1
  337. package/dist/page-extensions/WaitEventHandler.d.ts +20 -0
  338. package/dist/page-extensions/WaitEventHandler.js +20 -0
  339. package/dist/page-extensions/WaitEventHandler.js.map +1 -1
  340. package/dist/page-overrides/ClickOverride.d.ts +23 -2
  341. package/dist/page-overrides/ClickOverride.js +34 -50
  342. package/dist/page-overrides/ClickOverride.js.map +1 -1
  343. package/dist/page-overrides/FillOverride.d.ts +23 -0
  344. package/dist/page-overrides/FillOverride.js +56 -61
  345. package/dist/page-overrides/FillOverride.js.map +1 -1
  346. package/dist/services/ConfigBuilder.d.ts +24 -0
  347. package/dist/services/ConfigBuilder.js +24 -0
  348. package/dist/services/ConfigBuilder.js.map +1 -1
  349. package/dist/services/IndiciumApi.service.d.ts +26 -0
  350. package/dist/services/IndiciumApi.service.js +40 -5
  351. package/dist/services/IndiciumApi.service.js.map +1 -1
  352. package/dist/services/Logger.d.ts +13 -0
  353. package/dist/services/Logger.js +39 -0
  354. package/dist/services/Logger.js.map +1 -1
  355. package/dist/types/Components.d.ts +18 -1
  356. package/dist/types/Components.js +0 -1
  357. package/dist/types/Components.js.map +1 -1
  358. package/dist/types/LocatorType.d.ts +5 -0
  359. package/dist/types/LocatorType.js +2 -0
  360. package/dist/types/LocatorType.js.map +1 -0
  361. package/dist/types/PollTypes.d.ts +8 -0
  362. package/dist/types/Test.d.ts +18 -0
  363. package/dist/types/Universal.d.ts +12 -0
  364. package/dist/types/index.d.ts +2 -0
  365. package/dist/types/index.js +2 -0
  366. package/dist/types/index.js.map +1 -1
  367. package/enums/ElementTypes.ts +18 -0
  368. package/enums/ExportFormat.ts +8 -0
  369. package/enums/LogLevel.ts +17 -1
  370. package/enums/index.ts +1 -0
  371. package/helpers/ConfigChecker.ts +13 -0
  372. package/helpers/Ensure.ts +13 -0
  373. package/helpers/FlightTracker.ts +109 -20
  374. package/helpers/GlobalWaitEventHandler.ts +13 -0
  375. package/helpers/LoginHelper.ts +49 -12
  376. package/helpers/PathResolver.ts +22 -0
  377. package/helpers/Poll.ts +13 -1
  378. package/helpers/RegexHelper.ts +15 -3
  379. package/helpers/SubjectNavigator.ts +57 -0
  380. package/helpers/UserSimulationHelper.ts +14 -0
  381. package/helpers/index.ts +1 -0
  382. package/index.ts +1 -0
  383. package/interfaces/IComponentObjects.ts +12 -0
  384. package/interfaces/IComponentSchemaMeta.ts +17 -0
  385. package/interfaces/IProperty.ts +13 -0
  386. package/interfaces/IRegisteredSubjects.ts +12 -0
  387. package/interfaces/ISeedSubjectDraft.ts +17 -0
  388. package/interfaces/ISubject.ts +13 -0
  389. package/interfaces/ISubjectDetail.ts +12 -0
  390. package/mcp/ArtifactResolver.ts +296 -0
  391. package/mcp/index.ts +2 -0
  392. package/package.json +20 -8
  393. package/page-extensions/GlobalComponents.ts +30 -0
  394. package/page-extensions/GoToDeepLink.ts +9 -0
  395. package/page-extensions/LoginFeatures.ts +8 -0
  396. package/page-extensions/SubjectRegistry.ts +32 -0
  397. package/page-extensions/UserSimulation.ts +21 -0
  398. package/page-extensions/WaitEventHandler.ts +20 -0
  399. package/page-overrides/ClickOverride.ts +36 -55
  400. package/page-overrides/FillOverride.ts +59 -73
  401. package/promptCredentials.js +1 -1
  402. package/scripts/Testwise.template.json +1 -1
  403. package/scripts/diagram.js +2267 -0
  404. package/scripts/main.js +84 -63
  405. package/scripts/postinstall.js +55 -42
  406. package/scripts/setup.js +91 -37
  407. package/scripts/sync.js +767 -748
  408. package/services/ConfigBuilder.ts +24 -0
  409. package/services/IndiciumApi.service.ts +44 -6
  410. package/services/Logger.ts +40 -0
  411. package/templates/copilot-instructions.md +130 -0
  412. package/templates/mcp.json +9 -0
  413. package/templates/testwise-test-expert.agent.md +453 -0
  414. package/tests/tsconfig.json +12 -0
  415. package/tsconfig.json +6 -2
  416. package/types/Components.ts +17 -2
  417. package/types/LocatorType.ts +5 -0
  418. package/types/PollTypes.ts +8 -0
  419. package/types/Test.ts +18 -0
  420. package/types/Universal.ts +12 -0
  421. package/types/index.ts +2 -0
  422. package/dist/interfaces/IStoredTestResults.d.ts +0 -5
  423. package/dist/interfaces/IStoredTestResults.js +0 -2
  424. package/dist/interfaces/IStoredTestResults.js.map +0 -1
  425. package/dist/templates/test-artifacts/SubjectPageBase.d.ts +0 -5
  426. package/dist/templates/test-artifacts/SubjectPageBase.js +0 -6
  427. package/dist/templates/test-artifacts/SubjectPageBase.js.map +0 -1
  428. package/dist/templates/test-artifacts/screens/index.d.ts +0 -1
  429. package/dist/templates/test-artifacts/screens/index.js +0 -2
  430. package/dist/templates/test-artifacts/screens/index.js.map +0 -1
  431. package/dist/templates/test-artifacts/subjects/index.d.ts +0 -1
  432. package/dist/templates/test-artifacts/subjects/index.js +0 -2
  433. package/dist/templates/test-artifacts/subjects/index.js.map +0 -1
  434. package/interfaces/IStoredTestResults.ts +0 -6
@@ -1,32 +1,46 @@
1
1
  import * as fs from 'node:fs';
2
2
  import * as path from 'node:path';
3
- import { dirname } from 'node:path';
4
- import { fileURLToPath } from 'node:url';
5
- import { DataRetriever, NamingHandler } from '../index.js';
6
3
  import type { ISubject } from '../interfaces/ISubject.js';
7
- import {
8
- coreComponents,
9
- type ScreenComponents,
10
- type SubjectAgnosticComponents,
11
- screenComponents
12
- } from '../types/Components.js';
13
- import { type LocatorType, SelectorBuilder } from './SelectorBuilder.js';
14
-
4
+ import type { ScreenComponents } from '../types/Components.js';
5
+ import type { LocatorType } from '../types/LocatorType.js';
6
+ import { DataRetriever, NamingHandler, PipelinePaths } from './helpers/index.js';
7
+ import { SelectorBuilder } from './SelectorBuilder.js';
8
+ import { type ComponentEntry, SubjectClassModelBuilder } from './SubjectClassModelBuilder.js';
9
+ import { serializeTsFile } from './TsFileSerializer.js';
10
+
11
+ /**
12
+ * **Pipeline Step 6** — Generates typed TypeScript subject class files under
13
+ * `test-artifacts/subjects/<SubjectName>/`.
14
+ *
15
+ * **What it does:**
16
+ * - Reads `seed-data/subjectsToBuild.json` to get the list of subjects to
17
+ * generate.
18
+ * - For each subject, uses `SubjectClassModelBuilder` to produce an in-memory
19
+ * model of the class, then hands it to `TsFileSerializer` to write the
20
+ * TypeScript file to disk.
21
+ * - Each generated class extends `SubjectPageBase`, imports the matching
22
+ * screen interface, and declares typed component properties.
23
+ * - After generating all class files, writes an `index.ts` barrel file for
24
+ * each subject folder.
25
+ *
26
+ * **When it runs:** Step 6 of `testwise sync`, after `SubjectComponentGenerator`
27
+ * has written the component interface files.
28
+ */
15
29
  export class SubjectGenerator {
16
- private static readonly SUBJECTS_RELATIVE_PATH = 'test-artifacts/subjects';
17
-
18
- private readonly _currentFilename: string;
19
- private readonly _currentDirname: string;
20
30
  private readonly _subjectsDirectory: string;
31
+ private readonly _screensDirectory: string;
21
32
  private readonly _namingHandler: NamingHandler;
22
33
  private readonly _selectorBuilder: SelectorBuilder;
34
+ private readonly _paths: PipelinePaths;
35
+ private readonly _modelBuilder: SubjectClassModelBuilder;
23
36
 
24
- constructor() {
25
- this._currentFilename = fileURLToPath(import.meta.url);
26
- this._currentDirname = dirname(this._currentFilename);
27
- this._subjectsDirectory = path.resolve(this._currentDirname, `../../${SubjectGenerator.SUBJECTS_RELATIVE_PATH}`);
37
+ constructor(paths?: PipelinePaths) {
38
+ this._paths = paths ?? new PipelinePaths();
39
+ this._subjectsDirectory = this._paths.subjects;
40
+ this._screensDirectory = this._paths.screens;
28
41
  this._namingHandler = new NamingHandler();
29
42
  this._selectorBuilder = new SelectorBuilder();
43
+ this._modelBuilder = new SubjectClassModelBuilder(this._namingHandler, this._selectorBuilder);
30
44
  }
31
45
 
32
46
  public run(): void {
@@ -35,7 +49,7 @@ export class SubjectGenerator {
35
49
  }
36
50
 
37
51
  private generateSubjectClasses(): void {
38
- const subjects: ISubject[] = new DataRetriever().getSubjectsToBuild();
52
+ const subjects: ISubject[] = new DataRetriever(this._paths).getSubjectsToBuild();
39
53
 
40
54
  subjects.forEach((subject) => {
41
55
  this.createSubjectClass(subject);
@@ -78,38 +92,21 @@ export class SubjectGenerator {
78
92
  const screenInterfaceName = this._namingHandler.generateScreenInterfaceName(subject.screentype_id);
79
93
  const screenInterfacePath = this.getScreenInterfacePath(screenInterfaceName);
80
94
  const screenFileContent = fs.readFileSync(screenInterfacePath, 'utf-8');
81
- const subjectFolderName = this._namingHandler.toPascalCase(subject.subject);
95
+ const subjectFolderName = this._namingHandler.toSubjectPascalCase(subject.subject);
82
96
  const subjectFolderPath = this.getSubjectFolderRelativePath(subjectFolderName);
83
97
 
84
- const subjectClass = {
85
- content: `import type { Page } from '@playwright/test';\nimport { SubjectPageBase } from '../../SubjectPageBase.js';\n`,
86
- name: this._namingHandler.generateSubjectClassName(subject)
87
- };
88
- const componentDictionary: { name: string; type: SubjectAgnosticComponents; context: string }[] =
89
- this.getAllComponentsFromInterface(screenFileContent, screenInterfaceName, subject) as {
90
- name: string;
91
- type: SubjectAgnosticComponents;
92
- context: string;
93
- }[];
94
-
95
- this.addScreenInterfaceImport(subjectClass, screenInterfaceName);
96
- this.removeComponentImports(subjectClass);
97
- this.addCoreComponentImports(componentDictionary, subjectFolderName, subjectClass);
98
- this.addClassExport(subjectClass, screenInterfaceName);
99
- this.addComponentDeclarations(subjectClass, componentDictionary, subjectFolderName);
100
- this.addConstructor(subjectClass, componentDictionary, subjectFolderName, subject);
101
- this.addGoToMethod(subjectClass, subject);
102
- this.addSubjectClassLineEndings(subjectClass);
103
- this.verifyDirectoryExists(subjectFolderPath);
104
- fs.writeFileSync(path.join(subjectFolderPath, `${subjectClass.name}.ts`), subjectClass.content, 'utf-8');
105
- }
98
+ const componentDictionary = this.getAllComponentsFromInterface(
99
+ screenFileContent,
100
+ screenInterfaceName,
101
+ subject
102
+ ) as ComponentEntry[];
106
103
 
107
- private addGoToMethod(subjectClass: { content: string }, subject: ISubject): void {
108
- let url = `subject=${subject.subject}`;
104
+ const model = this._modelBuilder.build(subject, screenInterfaceName, componentDictionary, subjectFolderName);
105
+ const content = serializeTsFile(model);
109
106
 
110
- if (subject.variant !== '') url = `${url}/subjectVariant=${subject.variant}`;
111
-
112
- subjectClass.content += `\n public async goTo() {\n await this._subjectPage.goToDeepLink(\`${url}\`);\n await this._subjectPage.waitForLoadState('networkidle');\n }\n`;
107
+ this.verifyDirectoryExists(subjectFolderPath);
108
+ const className = this._namingHandler.generateSubjectClassName(subject);
109
+ fs.writeFileSync(path.join(subjectFolderPath, `${className}.ts`), content, 'utf-8');
113
110
  }
114
111
 
115
112
  private getAllComponentsFromInterface(
@@ -126,10 +123,17 @@ export class SubjectGenerator {
126
123
  if (interfaceMatches) {
127
124
  const propertyMatches = interfaceMatches[1].match(/^\s*([a-zA-Z0-9_]+)\s*:\s*([a-zA-Z0-9_]+);/gm);
128
125
  if (propertyMatches) {
126
+ const screenMeta = new DataRetriever(this._paths).getScreenComponentMeta(subject.screentype_id);
127
+
129
128
  componentDictionary = propertyMatches.map((line) => {
130
129
  // eslint-disable-next-line @typescript-eslint/no-unused-vars
131
130
  const [_, name, type] = line.match(/^\s*([a-zA-Z0-9_]+)\s*:\s*([a-zA-Z0-9_]+);/) || [];
132
- const context = this.generateComponentContextLocatorString(type as ScreenComponents, name, subject);
131
+ const context = this.generateComponentContextLocatorString(
132
+ type as ScreenComponents,
133
+ name,
134
+ subject,
135
+ screenMeta
136
+ );
133
137
 
134
138
  return { name, type, context };
135
139
  });
@@ -139,44 +143,23 @@ export class SubjectGenerator {
139
143
  return componentDictionary;
140
144
  }
141
145
 
142
- // ToDo: decide if this needs to move into a ContextGenerator class (depending on the complexity of context generation)
143
146
  private generateComponentContextLocatorString(
144
147
  componentType: ScreenComponents,
145
148
  componentName: string,
146
- subject: ISubject
149
+ subject: ISubject,
150
+ screenMeta: Record<string, string>
147
151
  ): string {
148
- const componentId = this._namingHandler.getComponentIdFromName(componentName, componentType);
149
- const screentypeId = subject.screentype_id.replace(/_/g, '-');
150
- const locatorString = {
151
- prefix: '',
152
- suffix: '',
153
- locatorType: 'getByTestId' as LocatorType
154
- };
155
-
156
- switch (componentType) {
157
- case 'Form':
158
- case 'Grid':
159
- case 'Splitter':
160
- case 'FilterForm':
161
- case 'Scheduler':
162
- locatorString.prefix = `screen__${screentypeId}__`;
163
- break;
164
- case 'ActionBar':
165
- case 'CustomActionBar':
166
- locatorString.prefix = '.';
167
- locatorString.locatorType = 'locator';
168
- break;
169
- case 'Tab':
170
- locatorString.prefix = '.Tab.';
171
- locatorString.locatorType = 'locator';
172
- break;
173
- case 'DetailTabPage':
174
- return `this.context`;
175
- }
176
-
177
- return `this.context.${locatorString.locatorType}('${locatorString.prefix}${componentId}${locatorString.suffix}')`;
152
+ return generateComponentContextLocatorString(
153
+ componentType,
154
+ componentName,
155
+ subject,
156
+ screenMeta,
157
+ this._namingHandler
158
+ );
178
159
  }
179
160
 
161
+ // ── Helpers ───────────────────────────────────────────────────────────────
162
+
180
163
  private verifyDirectoryExists(directoryPath: string): void {
181
164
  if (!fs.existsSync(directoryPath)) {
182
165
  fs.mkdirSync(directoryPath, { recursive: true });
@@ -184,10 +167,7 @@ export class SubjectGenerator {
184
167
  }
185
168
 
186
169
  private getScreenInterfacePath(screenInterfaceName: string): string {
187
- const screenInterfacePath = path.resolve(
188
- this._currentDirname,
189
- `../../test-artifacts/screens/${screenInterfaceName}.ts`
190
- );
170
+ const screenInterfacePath = path.join(this._screensDirectory, `${screenInterfaceName}.ts`);
191
171
 
192
172
  if (!fs.existsSync(screenInterfacePath)) {
193
173
  throw new Error(`Screen interface file not found: ${screenInterfacePath}`);
@@ -197,152 +177,59 @@ export class SubjectGenerator {
197
177
  }
198
178
 
199
179
  private getSubjectFolderRelativePath(subjectFolderName: string): string {
200
- const subjectFolderPath = path.resolve(
201
- this._currentDirname,
202
- `../../${SubjectGenerator.SUBJECTS_RELATIVE_PATH}/${subjectFolderName}`
203
- );
204
- return subjectFolderPath;
205
- }
206
-
207
- private addCoreComponentImports(
208
- componentDictionary: { name: string; type: SubjectAgnosticComponents }[],
209
- subjectFolderName: string,
210
- subjectClass: { content: string }
211
- ): void {
212
- const coreComponentImports = new Set<string>();
213
-
214
- componentDictionary.forEach((component) => {
215
- if (!screenComponents.includes(component.type)) return;
216
-
217
- if (coreComponents.includes(component.type)) {
218
- const importRegex = new RegExp(
219
- `import \\{[^}]*\\b${component.type}\\b[^}]*\\} from '../../../components/index.js';`
220
- );
221
-
222
- if (importRegex.test(subjectClass.content)) {
223
- return;
224
- }
225
-
226
- coreComponentImports.add(component.type);
227
- return;
228
- }
229
-
230
- const componentName = component.type;
231
- const componentImport = `import { type ${subjectFolderName}${componentName}, ${subjectFolderName}${componentName}Component } from './Components/${subjectFolderName}${componentName}.js';`;
232
-
233
- if (!subjectClass.content.includes(componentImport)) {
234
- subjectClass.content = `${componentImport}\n${subjectClass.content}`;
235
- }
236
- });
237
-
238
- if (coreComponentImports.size > 0) {
239
- subjectClass.content = `import { ${Array.from(coreComponentImports).join(', ')} } from '../../../components/index.js';\n${subjectClass.content}`;
240
- }
241
- }
242
-
243
- private removeComponentImports(subjectClass: { content: string }): void {
244
- subjectClass.content = subjectClass.content.replace(
245
- /import \{[^}]+\} from '\.\.\/\.\.\/components\/index\.js';\n?/g,
246
- ''
247
- );
248
- }
249
-
250
- private addClassExport(subjectClass: { content: string; name: string }, screenInterfaceName: string): void {
251
- subjectClass.content += `\nexport class ${subjectClass.name} extends SubjectPageBase implements ${screenInterfaceName} {\n`;
252
- }
253
-
254
- private addScreenInterfaceImport(subjectClass: { content: string }, screenInterfaceName: string): void {
255
- if (subjectClass.content.includes(`import type { ${screenInterfaceName} }`)) {
256
- return;
257
- }
258
-
259
- subjectClass.content = `import type { ${screenInterfaceName} } from '../../screens/index.js';\n${subjectClass.content}`;
260
- }
261
-
262
- private addComponentDeclarations(
263
- subjectClass: { content: string },
264
- componentDictionary: { name: string; type: SubjectAgnosticComponents }[],
265
- subjectFolderName: string
266
- ): void {
267
- componentDictionary.forEach((component) => {
268
- if (!screenComponents.includes(component.type)) return;
269
-
270
- const propertyName = this._namingHandler.formatPropertyName(component.name);
271
- if (coreComponents.includes(component.type)) {
272
- subjectClass.content += ` ${propertyName}: ${component.type};\n`;
273
- return;
274
- }
275
- const componentType = `${subjectFolderName}${component.type}`;
276
- subjectClass.content += ` ${propertyName}: ${componentType};\n`;
277
- });
278
-
279
- subjectClass.content += ` private _subjectPage: Page;\n`;
280
- }
281
-
282
- private addConstructor(
283
- subjectClass: { content: string },
284
- componentDictionary: { name: string; type: SubjectAgnosticComponents; context: string }[],
285
- subjectFolderName: string,
286
- subject: ISubject
287
- ): void {
288
- const rootContextSelector = this._selectorBuilder.getPageContext(subject);
289
-
290
- subjectClass.content += `\n constructor(page: Page) {\n super(page.locator('${rootContextSelector}'));\n`;
291
-
292
- componentDictionary.forEach((component) => {
293
- const propertyName = this._namingHandler.formatPropertyName(component.name);
294
-
295
- if (!screenComponents.includes(component.type)) return;
296
-
297
- if (coreComponents.includes(component.type)) {
298
- const componentId = this._namingHandler.toPascalCase(propertyName);
299
- subjectClass.content += ` this.${propertyName} = ${this.getComponentInitializer(component, componentId)};\n`;
300
- return;
301
- }
302
-
303
- const componentName = component.type;
304
- subjectClass.content += ` this.${propertyName} = new ${subjectFolderName}${componentName}Component(${component.context});\n`;
305
- });
306
-
307
- subjectClass.content += ` this._subjectPage = this.context.page();\n`;
308
- subjectClass.content += ` }\n`;
180
+ return this._paths.subjectFolder(subjectFolderName);
309
181
  }
182
+ }
310
183
 
311
- private getComponentInitializer(component: { type: string; context: string }, componentId: string): string {
312
- const componentNamePascal = this._namingHandler.toPascalCase(component.type);
313
-
314
- switch (component.type) {
315
- case 'Cardlist':
316
- case 'TaskTiles':
317
- case 'PrefilterList':
318
- case 'Chart':
319
- case 'CubeViewBar':
320
- case 'PivotGrid':
321
- case 'PivotGridFieldList':
322
- case 'Maps':
323
- case 'ReportBar':
324
- case 'ReportTiles':
325
- case 'Preview':
326
- return `new ${component.type}(this.context.locator('.${component.type}.${componentNamePascal}'))`;
327
- case 'CombinedFilter':
328
- case 'CustomActionBar':
329
- case 'ActionBar':
330
- case 'Splitter':
331
- case 'DetailTabPage':
332
- case 'Tab':
333
- case 'FilterForm':
334
- case 'Scheduler':
335
- return `new ${component.type}(${component.context})`;
336
- case 'TreeView':
337
- return `new ${component.type}(this.context.locator('.Tree.${componentNamePascal}'))`;
338
- case 'TaskBar':
339
- return `new ${component.type}(this.context.locator('.ActionBar.${componentId}'))`;
340
- default:
341
- throw new Error(`Unknown core component type: ${component.type}`);
184
+ /**
185
+ * Builds the Playwright locator expression string for a given screen component.
186
+ *
187
+ * Exported as a standalone function so that it can be unit-tested independently
188
+ * of the file-I/O-coupled {@link SubjectGenerator} class.
189
+ */
190
+ export function generateComponentContextLocatorString(
191
+ componentType: ScreenComponents,
192
+ componentName: string,
193
+ subject: ISubject,
194
+ screenMeta: Record<string, string>,
195
+ namingHandler: NamingHandler
196
+ ): string {
197
+ // Normalize the quicktype property name to the same form used as key in the meta map.
198
+ const normalizedName = componentName.toLowerCase().replace(/[^a-z0-9]/g, '');
199
+ const originalId = screenMeta[normalizedName];
200
+
201
+ const screentypeId = subject.screentype_id.replace(/_/g, '-');
202
+ const locatorString = {
203
+ prefix: '',
204
+ locatorType: 'getByTestId' as LocatorType
205
+ };
206
+
207
+ switch (componentType) {
208
+ case 'Form':
209
+ case 'Grid':
210
+ case 'Splitter':
211
+ case 'FilterForm':
212
+ case 'Scheduler': {
213
+ // data-testid uses lowercase with hyphens: e.g. Grid_QT3UL7F8 → grid-qt3ul7f8
214
+ const testId = originalId ? originalId.toLowerCase().replace(/_/g, '-') : componentName.toLowerCase();
215
+ locatorString.prefix = `screen__${screentypeId}__`;
216
+ return `this.context.getByTestId('${locatorString.prefix}${testId}')`;
342
217
  }
343
- }
344
-
345
- private addSubjectClassLineEndings(subjectClass: { content: string }): void {
346
- subjectClass.content += `}\n`;
347
- }
218
+ case 'ActionBar':
219
+ case 'CustomActionBar':
220
+ locatorString.prefix = '.';
221
+ locatorString.locatorType = 'locator';
222
+ break;
223
+ case 'Tab':
224
+ locatorString.prefix = '.Tab.';
225
+ locatorString.locatorType = 'locator';
226
+ break;
227
+ case 'DetailTabPage':
228
+ return `this.context`;
229
+ }
230
+
231
+ // For CSS class selectors (ActionBar, Tab): use the original ID as-is, fall back to
232
+ // capitalizing the first letter (handles consolidated 'tab' / 'detailTab' properties).
233
+ const cssId = originalId ?? namingHandler.capitalizeFirstLetter(componentName);
234
+ return `this.context.${locatorString.locatorType}('${locatorString.prefix}${cssId}')`;
348
235
  }
@@ -1,20 +1,39 @@
1
1
  import * as fs from 'node:fs';
2
2
  import * as path from 'node:path';
3
- import { dirname } from 'node:path';
4
- import { fileURLToPath } from 'node:url';
5
3
  import * as prettier from 'prettier';
6
-
4
+ import type { ISubjectDetail, ScreenContext } from '../interfaces/ISubjectDetail.js';
5
+ import { PipelinePaths } from './helpers/PipelinePaths.js';
6
+
7
+ /**
8
+ * **Pipeline Step 7** — Registers all generated subject classes into
9
+ * `page-extensions/SubjectRegistry.ts` so they are available on
10
+ * `page.subject.<ClassName>` during tests.
11
+ *
12
+ * **What it does:**
13
+ * - Scans `test-artifacts/subjects/` to discover every generated class file.
14
+ * - Reads `templates/SubjectRegistry.template.ts` as the implementation skeleton.
15
+ * - Injects import statements and property declarations for every discovered
16
+ * class into the template and writes the result to
17
+ * `page-extensions/SubjectRegistry.ts`.
18
+ * - Runs `prettier` over the output so the generated file passes lint.
19
+ *
20
+ * **Important:** Never edit `SubjectRegistry.ts` directly — it is
21
+ * overwritten on every `testwise sync`. Edit the template instead.
22
+ *
23
+ * **When it runs:** The final step (step 7) of `testwise sync`.
24
+ */
7
25
  export class SubjectRegistration {
8
26
  private static readonly IMPORT_MATCH_REGEX = /import .*'\.\.\/test-artifacts\/subjects\/index\.js';\n?/g;
9
27
 
10
- private readonly _currentFilename: string;
11
- private readonly _currentDirname: string;
12
28
  private readonly _subjectTypePath: string;
13
-
14
- constructor() {
15
- this._currentFilename = fileURLToPath(import.meta.url);
16
- this._currentDirname = dirname(this._currentFilename);
17
- this._subjectTypePath = path.resolve(this._currentDirname, '../../page-extensions/SubjectRegistry.ts');
29
+ private readonly _subjectsDirectory: string;
30
+ private readonly _registryTemplatePath: string;
31
+
32
+ constructor(paths?: PipelinePaths) {
33
+ const p = paths ?? new PipelinePaths();
34
+ this._subjectTypePath = p.subjectRegistry;
35
+ this._subjectsDirectory = p.subjects;
36
+ this._registryTemplatePath = p.subjectRegistryTemplate;
18
37
  }
19
38
 
20
39
  public async run(): Promise<void> {
@@ -24,20 +43,16 @@ export class SubjectRegistration {
24
43
  }
25
44
 
26
45
  public resetSubjectRegistry(): void {
27
- const root = path.resolve(this._currentDirname, '../../');
28
- const registryPath = path.join(root, 'page-extensions', 'SubjectRegistry.ts');
29
- const templatePath = path.join(root, 'templates', 'SubjectRegistry.template.ts');
30
-
31
- if (fs.existsSync(registryPath)) {
32
- fs.rmSync(registryPath, { force: true });
46
+ if (fs.existsSync(this._subjectTypePath)) {
47
+ fs.rmSync(this._subjectTypePath, { force: true });
33
48
  }
34
49
 
35
- if (fs.existsSync(templatePath)) {
36
- fs.copyFileSync(templatePath, registryPath);
50
+ if (fs.existsSync(this._registryTemplatePath)) {
51
+ fs.copyFileSync(this._registryTemplatePath, this._subjectTypePath);
37
52
  }
38
53
  }
39
54
 
40
- private async registerGeneratedSubjectsAsSubjectTypes(subjectDetails: SubjectDetail[]): Promise<void> {
55
+ private async registerGeneratedSubjectsAsSubjectTypes(subjectDetails: ISubjectDetail[]): Promise<void> {
41
56
  const subjectTypeImportsAndExports = this.buildSubjectTypeExport(subjectDetails);
42
57
  const subject = { content: this.setSubjectTypeContent() };
43
58
 
@@ -75,7 +90,7 @@ export class SubjectRegistration {
75
90
  }
76
91
  }
77
92
 
78
- private buildSubjectTypeExport(subjectDetails: SubjectDetail[]): string {
93
+ private buildSubjectTypeExport(subjectDetails: ISubjectDetail[]): string {
79
94
  const subjectTypeEntries = subjectDetails
80
95
  .map(
81
96
  (details) =>
@@ -91,13 +106,13 @@ export class SubjectRegistration {
91
106
  return newSubjectTypes;
92
107
  }
93
108
 
94
- private addPathRecordsToContent(content: string, subjectDetails: SubjectDetail[]): string {
109
+ private addPathRecordsToContent(content: string, subjectDetails: ISubjectDetail[]): string {
95
110
  const pathRecordsString = this.buildPathRecordsString(subjectDetails);
96
111
  const stringToMatch = "none: ''";
97
112
  return content.replace(stringToMatch, `\n${pathRecordsString}\n `);
98
113
  }
99
114
 
100
- private buildPathRecordsString(subjectDetails: SubjectDetail[]): string {
115
+ private buildPathRecordsString(subjectDetails: ISubjectDetail[]): string {
101
116
  return subjectDetails
102
117
  .map(
103
118
  (details) =>
@@ -107,14 +122,14 @@ export class SubjectRegistration {
107
122
  .join('\n ');
108
123
  }
109
124
 
110
- private getAllSubjectDetails(): SubjectDetail[] {
111
- const subjectsDir = path.resolve(this._currentDirname, '../../test-artifacts/subjects');
125
+ private getAllSubjectDetails(): ISubjectDetail[] {
126
+ const subjectsDir = this._subjectsDirectory;
112
127
 
113
128
  const subjectFolders = fs.readdirSync(subjectsDir).filter((file) => {
114
129
  return fs.statSync(path.join(subjectsDir, file)).isDirectory();
115
130
  });
116
131
 
117
- const subjectDetails: SubjectDetail[] = [];
132
+ const subjectDetails: ISubjectDetail[] = [];
118
133
  const seenFullNames = new Set<string>();
119
134
 
120
135
  subjectFolders.forEach((folder) => {
@@ -134,7 +149,7 @@ export class SubjectRegistration {
134
149
  const fullName = variantMatch[0];
135
150
  if (!seenFullNames.has(fullName)) {
136
151
  const variant = variantMatch[2] || '';
137
- const screen = variantMatch[3] as SubjectDetail['screen'];
152
+ const screen = variantMatch[3] as ScreenContext;
138
153
 
139
154
  subjectDetails.push({
140
155
  subject: folder,
@@ -150,9 +165,3 @@ export class SubjectRegistration {
150
165
  return subjectDetails;
151
166
  }
152
167
  }
153
-
154
- export interface SubjectDetail {
155
- subject: string;
156
- variant?: string;
157
- screen: 'Main' | 'Popup' | 'Zoom' | 'Detail';
158
- }
@@ -0,0 +1,94 @@
1
+ /**
2
+ * Represents a single named import member.
3
+ * Set `isTypeOnly` for inline `type` keyword, e.g. `import { type IFoo, Bar }`.
4
+ */
5
+ export interface TsNamedImport {
6
+ name: string;
7
+ isTypeOnly?: boolean;
8
+ }
9
+
10
+ /**
11
+ * Represents a single import statement in a TypeScript file.
12
+ * Set `isTypeOnly` at the top level for `import type { ... }`.
13
+ */
14
+ export interface TsImport {
15
+ namedImports: TsNamedImport[];
16
+ isTypeOnly: boolean;
17
+ from: string;
18
+ }
19
+
20
+ /** Represents a class property declaration. */
21
+ export interface TsProperty {
22
+ access?: 'private';
23
+ name: string;
24
+ type: string;
25
+ }
26
+
27
+ /** Represents a `this.x = value;` assignment inside a constructor. */
28
+ export interface TsConstructorAssignment {
29
+ property: string;
30
+ value: string;
31
+ }
32
+
33
+ /** Represents a class constructor. */
34
+ export interface TsConstructor {
35
+ params: Array<{ name: string; type: string }>;
36
+ superCall: string;
37
+ assignments: TsConstructorAssignment[];
38
+ extraLines: string[];
39
+ }
40
+
41
+ /** Represents a class method. */
42
+ export interface TsMethod {
43
+ isAsync: boolean;
44
+ name: string;
45
+ returnType: string;
46
+ bodyLines: string[];
47
+ }
48
+
49
+ /** Represents a TypeScript class declaration. */
50
+ export interface TsClass {
51
+ name: string;
52
+ extendsClass: string;
53
+ implementsInterface: string;
54
+ properties: TsProperty[];
55
+ constructor: TsConstructor;
56
+ methods?: TsMethod[];
57
+ }
58
+
59
+ /** Top-level model for a generated TypeScript subject class file. */
60
+ export interface TsFileModel {
61
+ imports: TsImport[];
62
+ classModel: TsClass;
63
+ }
64
+
65
+ /** Represents a typed property in a component class. */
66
+ export interface ComponentPropertyModel {
67
+ name: string;
68
+ type: string;
69
+ }
70
+
71
+ /** Represents a `this.x = value;` assignment in a component class constructor. */
72
+ export interface ComponentAssignmentModel {
73
+ property: string;
74
+ value: string;
75
+ }
76
+
77
+ /** Represents a getter in a Grid component class. */
78
+ export interface ComponentGetterModel {
79
+ name: string;
80
+ returnType: string;
81
+ bodyLine: string;
82
+ }
83
+
84
+ /**
85
+ * Represents the class body to append to a component interface file.
86
+ * Properties and assignments apply to Form; getters apply to Grid.
87
+ */
88
+ export interface ComponentClassModel {
89
+ interfaceName: string;
90
+ componentType: string;
91
+ properties: ComponentPropertyModel[];
92
+ assignments: ComponentAssignmentModel[];
93
+ getters: ComponentGetterModel[];
94
+ }