testeranto 0.200.1 → 0.202.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 (373) hide show
  1. package/README.md +26 -1
  2. package/design-editor/DesignEditor.tsx +40 -241
  3. package/dist/common/design-editor/DesignEditor.js +33 -198
  4. package/dist/common/src/App.js +158 -16
  5. package/dist/common/src/PM/PM_WithBuild.js +135 -0
  6. package/dist/common/src/PM/PM_WithEslintAndTsc.js +79 -67
  7. package/dist/common/src/PM/PM_WithGit.js +517 -0
  8. package/dist/common/src/PM/PM_WithProcesses.js +519 -0
  9. package/dist/common/src/PM/PM_WithWebSocket.js +535 -0
  10. package/dist/common/src/PM/base.js +62 -0
  11. package/dist/common/src/PM/main.js +533 -1676
  12. package/dist/common/src/PM/metafileOutputs.js +78 -0
  13. package/dist/common/src/PM/node.js +0 -6
  14. package/dist/common/src/PM/pure.js +0 -8
  15. package/dist/common/src/PM/types.js +1 -0
  16. package/dist/common/src/PM/utils.js +210 -0
  17. package/dist/common/src/PM/web.js +0 -6
  18. package/dist/common/src/ReportServer.js +0 -10
  19. package/dist/common/src/ReportServerLib.js +0 -140
  20. package/dist/common/src/components/pure/AppFrame.js +68 -56
  21. package/dist/common/src/components/pure/ArtifactTree.js +80 -0
  22. package/dist/common/src/components/pure/BuildLogViewer.js +106 -0
  23. package/dist/common/src/components/pure/DebugEnv.js +30 -0
  24. package/dist/common/src/components/pure/FileTree.js +34 -0
  25. package/dist/common/src/components/pure/FileTreeItem.js +29 -0
  26. package/dist/common/src/components/pure/GitHubLoginButton.js +18 -0
  27. package/dist/common/src/components/pure/GitIntegrationView.js +342 -0
  28. package/dist/common/src/components/pure/ProcessManager.js +1 -0
  29. package/dist/common/src/components/pure/ProcessManagerView.js +73 -74
  30. package/dist/common/src/components/pure/ProjectPageView.js +4 -117
  31. package/dist/common/src/components/pure/Settings.js +121 -0
  32. package/dist/common/src/components/pure/Settings.test.js +34 -0
  33. package/dist/common/src/components/pure/SignIn.js +22 -0
  34. package/dist/common/src/components/pure/SingleProcessView.js +166 -213
  35. package/dist/common/src/components/pure/TestPageView.js +113 -368
  36. package/dist/common/src/components/pure/TestPageView_utils.js +117 -0
  37. package/dist/common/src/components/pure/TestTable.js +33 -0
  38. package/dist/common/src/components/pure/ToastNotification.js +14 -0
  39. package/dist/common/src/components/pure/UserProfile.js +27 -0
  40. package/dist/common/src/components/stateful/AuthCallbackPage.js +51 -0
  41. package/dist/common/src/components/stateful/FeaturesReporter.js +2 -1
  42. package/dist/common/src/components/stateful/FileTree.js +58 -39
  43. package/dist/common/src/components/stateful/GitIntegrationPage.js +12 -0
  44. package/dist/common/src/components/stateful/ProcessManagerPage.js +13 -15
  45. package/dist/common/src/components/stateful/ProjectPage.js +6 -5
  46. package/dist/common/src/components/stateful/ProjectsPage.js +17 -19
  47. package/dist/common/src/components/stateful/SingleProcessPage.js +16 -26
  48. package/dist/common/src/components/stateful/TestPage.js +7 -5
  49. package/dist/common/src/hooks/useGitMode.js +21 -0
  50. package/dist/common/src/lib/BaseSuite.test/mock.js +15 -8
  51. package/dist/common/src/lib/BaseSuite.test/test.js +56 -80
  52. package/dist/common/src/lib/Tiposkripto.js +24 -0
  53. package/dist/common/src/lib/Tiposkripto.test/MockTiposkripto.js +154 -10
  54. package/dist/common/src/lib/Tiposkripto.test/Tiposkripto.adapter.js +6 -12
  55. package/dist/common/src/lib/Tiposkripto.test/Tiposkripto.implementation.js +63 -23
  56. package/dist/common/src/lib/Tiposkripto.test/Tiposkripto.specification.js +14 -6
  57. package/dist/common/src/lib/pmProxy.test/specification.js +167 -52
  58. package/dist/common/src/services/FileService.js +505 -0
  59. package/dist/common/src/services/GitHubAuthService.js +184 -0
  60. package/dist/common/src/testeranto.js +38 -97
  61. package/dist/common/src/utils/api.js +12 -8
  62. package/dist/common/src/utils/gitTest.js +27 -0
  63. package/dist/common/src/utils.js +23 -13
  64. package/dist/common/testeranto.config.js +21 -17
  65. package/dist/common/tsconfig.common.tsbuildinfo +1 -1
  66. package/dist/module/design-editor/DesignEditor.js +33 -199
  67. package/dist/module/src/App.js +121 -15
  68. package/dist/module/src/PM/PM_WithBuild.js +128 -0
  69. package/dist/module/src/PM/PM_WithEslintAndTsc.js +79 -67
  70. package/dist/module/src/PM/PM_WithGit.js +477 -0
  71. package/dist/module/src/PM/PM_WithProcesses.js +479 -0
  72. package/dist/module/src/PM/PM_WithWebSocket.js +528 -0
  73. package/dist/module/src/PM/base.js +62 -0
  74. package/dist/module/src/PM/main.js +533 -1676
  75. package/dist/module/src/PM/metafileOutputs.js +78 -0
  76. package/dist/module/src/PM/node.js +0 -6
  77. package/dist/module/src/PM/pure.js +0 -8
  78. package/dist/module/src/PM/types.js +1 -1
  79. package/dist/module/src/PM/utils.js +196 -0
  80. package/dist/module/src/PM/web.js +0 -6
  81. package/dist/module/src/ReportServer.js +1 -9
  82. package/dist/module/src/ReportServerLib.js +1 -134
  83. package/dist/module/src/components/pure/AppFrame.js +66 -24
  84. package/dist/module/src/components/pure/ArtifactTree.js +80 -0
  85. package/dist/module/src/components/pure/BuildLogViewer.js +99 -0
  86. package/dist/module/src/components/pure/DebugEnv.js +23 -0
  87. package/dist/module/src/components/pure/FileTree.js +27 -0
  88. package/dist/module/src/components/pure/FileTreeItem.js +22 -0
  89. package/dist/module/src/components/pure/GitHubLoginButton.js +11 -0
  90. package/dist/module/src/components/pure/GitIntegrationView.js +305 -0
  91. package/dist/module/src/components/pure/ProcessManager.js +1 -0
  92. package/dist/module/src/components/pure/ProcessManagerView.js +74 -75
  93. package/dist/module/src/components/pure/ProjectPageView.js +5 -118
  94. package/dist/module/src/components/pure/Settings.js +84 -0
  95. package/dist/module/src/components/pure/Settings.test.js +29 -0
  96. package/dist/module/src/components/pure/SignIn.js +15 -0
  97. package/dist/module/src/components/pure/SingleProcessView.js +130 -214
  98. package/dist/module/src/components/pure/TestPageView.js +97 -352
  99. package/dist/module/src/components/pure/TestPageView_utils.js +109 -0
  100. package/dist/module/src/components/pure/TestTable.js +26 -0
  101. package/dist/module/src/components/pure/ToastNotification.js +7 -0
  102. package/dist/module/src/components/pure/UserProfile.js +20 -0
  103. package/dist/module/src/components/stateful/AuthCallbackPage.js +14 -0
  104. package/dist/module/src/components/stateful/FeaturesReporter.js +2 -1
  105. package/dist/module/src/components/stateful/FileTree.js +59 -33
  106. package/dist/module/src/components/stateful/GitIntegrationPage.js +5 -0
  107. package/dist/module/src/components/stateful/ProcessManagerPage.js +13 -15
  108. package/dist/module/src/components/stateful/ProjectPage.js +6 -5
  109. package/dist/module/src/components/stateful/ProjectsPage.js +16 -18
  110. package/dist/module/src/components/stateful/SingleProcessPage.js +16 -26
  111. package/dist/module/src/components/stateful/TestPage.js +8 -6
  112. package/dist/module/src/hooks/useGitMode.js +17 -0
  113. package/dist/module/src/lib/BaseSuite.test/mock.js +15 -8
  114. package/dist/module/src/lib/BaseSuite.test/test.js +56 -80
  115. package/dist/module/src/lib/Tiposkripto.js +24 -0
  116. package/dist/module/src/lib/Tiposkripto.test/MockTiposkripto.js +154 -10
  117. package/dist/module/src/lib/Tiposkripto.test/Tiposkripto.adapter.js +6 -12
  118. package/dist/module/src/lib/Tiposkripto.test/Tiposkripto.implementation.js +63 -23
  119. package/dist/module/src/lib/Tiposkripto.test/Tiposkripto.specification.js +14 -6
  120. package/dist/module/src/lib/pmProxy.test/specification.js +167 -52
  121. package/dist/module/src/services/FileService.js +468 -0
  122. package/dist/module/src/services/GitHubAuthService.js +180 -0
  123. package/dist/module/src/testeranto.js +38 -97
  124. package/dist/module/src/utils/api.js +10 -7
  125. package/dist/module/src/utils/gitTest.js +23 -0
  126. package/dist/module/src/utils.js +21 -12
  127. package/dist/module/testeranto.config.js +21 -17
  128. package/dist/module/tsconfig.module.tsbuildinfo +1 -1
  129. package/dist/prebuild/App.css +94 -121
  130. package/dist/prebuild/App.js +44601 -11225
  131. package/dist/prebuild/testeranto.mjs +3113 -2256
  132. package/dist/types/design-editor/DesignEditor.d.ts +1 -18
  133. package/dist/types/src/App.d.ts +18 -0
  134. package/dist/types/src/PM/PM_WithBuild.d.ts +13 -0
  135. package/dist/types/src/PM/PM_WithEslintAndTsc.d.ts +2 -4
  136. package/dist/types/src/PM/PM_WithGit.d.ts +27 -0
  137. package/dist/types/src/PM/PM_WithProcesses.d.ts +29 -0
  138. package/dist/types/src/PM/PM_WithWebSocket.d.ts +108 -0
  139. package/dist/types/src/PM/base.d.ts +1 -1
  140. package/dist/types/src/PM/index.d.ts +0 -2
  141. package/dist/types/src/PM/main.d.ts +6 -77
  142. package/dist/types/src/PM/metafileOutputs.d.ts +0 -0
  143. package/dist/types/src/PM/node.d.ts +0 -2
  144. package/dist/types/src/PM/pure.d.ts +0 -2
  145. package/dist/types/src/PM/types.d.ts +118 -0
  146. package/dist/types/src/PM/utils.d.ts +35 -0
  147. package/dist/types/src/PM/web.d.ts +0 -2
  148. package/dist/types/src/Pure.d.ts +6 -1
  149. package/dist/types/src/ReportServer.d.ts +0 -1
  150. package/dist/types/src/ReportServerLib.d.ts +0 -1
  151. package/dist/types/src/Types.d.ts +1 -0
  152. package/dist/types/src/components/pure/ArtifactTree.d.ts +0 -0
  153. package/dist/types/src/components/pure/BuildLogViewer.d.ts +7 -0
  154. package/dist/types/src/components/pure/DebugEnv.d.ts +2 -0
  155. package/dist/types/src/components/pure/FileTree.d.ts +6 -0
  156. package/dist/types/src/components/pure/FileTreeItem.d.ts +8 -0
  157. package/dist/types/src/components/pure/GitHubLoginButton.d.ts +8 -0
  158. package/dist/types/src/components/pure/GitIntegrationView.d.ts +1 -0
  159. package/dist/types/src/components/pure/Settings.d.ts +1 -0
  160. package/dist/types/src/components/pure/Settings.test.d.ts +1 -0
  161. package/dist/types/src/components/pure/SignIn.d.ts +1 -0
  162. package/dist/types/src/components/pure/SingleProcessView.d.ts +10 -0
  163. package/dist/types/src/components/pure/TestPageView.d.ts +2 -1
  164. package/dist/types/src/components/pure/TestPageView_utils.d.ts +23 -0
  165. package/dist/types/src/components/pure/TestTable.d.ts +16 -0
  166. package/dist/types/src/components/pure/ToastNotification.d.ts +6 -0
  167. package/dist/types/src/components/pure/UserProfile.d.ts +2 -0
  168. package/dist/types/src/components/stateful/AuthCallbackPage.d.ts +2 -0
  169. package/dist/types/src/components/stateful/FileTree.d.ts +0 -8
  170. package/dist/types/src/components/stateful/GitIntegrationPage.d.ts +1 -0
  171. package/dist/types/src/hooks/useGitMode.d.ts +7 -0
  172. package/dist/types/src/lib/BaseSuite.test/mock.d.ts +2 -2
  173. package/dist/types/src/lib/BaseSuite.test/test.d.ts +4 -3
  174. package/dist/types/src/lib/Tiposkripto.d.ts +2 -0
  175. package/dist/types/src/lib/Tiposkripto.test/MockTiposkripto.d.ts +3 -0
  176. package/dist/types/src/lib/Tiposkripto.test/Tiposkripto.types.d.ts +5 -0
  177. package/dist/types/src/lib/index.d.ts +6 -0
  178. package/dist/types/src/services/FileService.d.ts +34 -0
  179. package/dist/types/src/services/GitHubAuthService.d.ts +32 -0
  180. package/dist/types/src/utils/api.d.ts +1 -0
  181. package/dist/types/src/utils/gitTest.d.ts +11 -0
  182. package/dist/types/src/utils.d.ts +3 -3
  183. package/dist/types/tsconfig.types.tsbuildinfo +1 -1
  184. package/example/__pycache__/Calculator.cpython-313.pyc +0 -0
  185. package/example/vendor/github.com/adamwong246/testeranto/src/golingvu/README.md +187 -0
  186. package/example/vendor/github.com/adamwong246/testeranto/src/golingvu/base_given.go +163 -0
  187. package/example/vendor/github.com/adamwong246/testeranto/src/golingvu/base_suite.go +85 -0
  188. package/example/vendor/github.com/adamwong246/testeranto/src/golingvu/base_then.go +21 -0
  189. package/example/vendor/github.com/adamwong246/testeranto/src/golingvu/base_when.go +21 -0
  190. package/example/vendor/github.com/adamwong246/testeranto/src/golingvu/golingvu.go +554 -0
  191. package/example/vendor/github.com/adamwong246/testeranto/src/golingvu/test_adapter.go +33 -0
  192. package/example/vendor/github.com/adamwong246/testeranto/src/golingvu/types.go +72 -0
  193. package/example/vendor/modules.txt +5 -0
  194. package/git-integration-plan.md +395 -0
  195. package/package.json +26 -14
  196. package/src/App.tsx +169 -18
  197. package/src/PM/PM_WithBuild.ts +171 -0
  198. package/src/PM/PM_WithEslintAndTsc.ts +109 -86
  199. package/src/PM/PM_WithGit.ts +585 -0
  200. package/src/PM/PM_WithProcesses.ts +639 -0
  201. package/src/PM/PM_WithWebSocket.ts +631 -0
  202. package/src/PM/base.ts +63 -1
  203. package/src/PM/index.ts +8 -5
  204. package/src/PM/main.ts +672 -2050
  205. package/src/PM/metafileOutputs.ts +90 -0
  206. package/src/PM/node.ts +18 -18
  207. package/src/PM/pure.ts +5 -13
  208. package/src/PM/types.ts +145 -0
  209. package/src/PM/utils.ts +256 -0
  210. package/src/PM/web.ts +8 -8
  211. package/src/README.md +122 -0
  212. package/src/ReportServer.ts +0 -12
  213. package/src/ReportServerLib.ts +0 -147
  214. package/src/Types.ts +1 -0
  215. package/src/app.scss +14 -164
  216. package/src/components/pure/AppFrame.tsx +237 -71
  217. package/src/components/pure/ArtifactTree.tsx +82 -0
  218. package/src/components/pure/BuildLogViewer.tsx +168 -0
  219. package/src/components/pure/DebugEnv.tsx +30 -0
  220. package/src/components/pure/FileTree.tsx +58 -0
  221. package/src/components/pure/FileTreeItem.tsx +49 -0
  222. package/src/components/pure/GitHubLoginButton.tsx +31 -0
  223. package/src/components/pure/GitIntegrationView.tsx +443 -0
  224. package/src/components/pure/ProcessManager.tsx +6 -5
  225. package/src/components/pure/ProcessManagerView.tsx +162 -166
  226. package/src/components/pure/ProjectPageView.tsx +6 -224
  227. package/src/components/pure/Settings.test.tsx +34 -0
  228. package/src/components/pure/Settings.tsx +163 -0
  229. package/src/components/pure/SignIn.tsx +33 -0
  230. package/src/components/pure/SingleProcessView.tsx +231 -235
  231. package/src/components/pure/TestPageView.test/specification.ts +1 -0
  232. package/src/components/pure/TestPageView.tsx +317 -826
  233. package/src/components/pure/TestPageView_utils.tsx +285 -0
  234. package/src/components/pure/TestTable.tsx +88 -0
  235. package/src/components/pure/ToastNotification.tsx +19 -0
  236. package/src/components/pure/UserProfile.tsx +44 -0
  237. package/src/components/stateful/AuthCallbackPage.tsx +21 -0
  238. package/src/components/stateful/FeaturesReporter.tsx +3 -1
  239. package/src/components/stateful/FileTree.tsx +58 -58
  240. package/src/components/stateful/GitIntegrationPage.tsx +8 -0
  241. package/src/components/stateful/ProcessManagerPage.tsx +13 -17
  242. package/src/components/stateful/ProjectPage.tsx +6 -5
  243. package/src/components/stateful/ProjectsPage.tsx +17 -19
  244. package/src/components/stateful/SVGEditor/CircleForm.tsx +68 -0
  245. package/src/components/stateful/SVGEditor/GroupForm.tsx +56 -0
  246. package/src/components/stateful/SVGEditor/RectForm.tsx +74 -0
  247. package/src/components/stateful/SVGEditor/SVGAttributeField.tsx +29 -0
  248. package/src/components/stateful/SVGEditor/SVGAttributesEditor.tsx +73 -0
  249. package/src/components/stateful/SVGEditor/SVGEditorControls.tsx +45 -0
  250. package/src/components/stateful/SVGEditor/SVGElementForm.tsx +45 -0
  251. package/src/components/stateful/SVGEditor/SVGPreview.tsx +225 -0
  252. package/src/components/stateful/SVGEditor/SVGTextEditor.tsx +166 -0
  253. package/src/components/stateful/SVGEditor/SVGTree.tsx +159 -0
  254. package/src/components/stateful/SVGEditor/SVGTypes.ts +36 -0
  255. package/src/components/stateful/SVGEditor/svg.xsd.xml +3038 -0
  256. package/src/components/stateful/SVGEditorPage.tsx +503 -0
  257. package/src/components/stateful/SingleProcessPage.tsx +18 -31
  258. package/src/components/stateful/TestPage.tsx +25 -22
  259. package/src/golingvu/golingvu.go +38 -2
  260. package/src/hooks/useGitMode.ts +20 -0
  261. package/src/lib/BaseSuite.test/mock.ts +16 -10
  262. package/src/lib/BaseSuite.test/test.ts +144 -103
  263. package/src/lib/Tiposkripto.test/MockTiposkripto.ts +178 -14
  264. package/src/lib/Tiposkripto.test/Tiposkripto.adapter.ts +9 -14
  265. package/src/lib/Tiposkripto.test/Tiposkripto.implementation.ts +78 -38
  266. package/src/lib/Tiposkripto.test/Tiposkripto.specification.ts +51 -9
  267. package/src/lib/Tiposkripto.test/Tiposkripto.types.ts +5 -0
  268. package/src/lib/Tiposkripto.ts +27 -0
  269. package/src/lib/index.ts +7 -0
  270. package/src/lib/pmProxy.test/specification.ts +168 -166
  271. package/src/pitono/PM/__pycache__/python.cpython-313.pyc +0 -0
  272. package/src/pitono/__pycache__/Pitono.cpython-313.pyc +0 -0
  273. package/src/pitono/__pycache__/__init__.cpython-313.pyc +0 -0
  274. package/src/pitono/__pycache__/base_given.cpython-313.pyc +0 -0
  275. package/src/pitono/__pycache__/base_suite.cpython-313.pyc +0 -0
  276. package/src/pitono/__pycache__/base_then.cpython-313.pyc +0 -0
  277. package/src/pitono/__pycache__/base_when.cpython-313.pyc +0 -0
  278. package/src/pitono/__pycache__/core_generator.cpython-313.pyc +0 -0
  279. package/src/pitono/__pycache__/simple_adapter.cpython-313.pyc +0 -0
  280. package/src/pitono/__pycache__/types.cpython-313.pyc +0 -0
  281. package/src/services/FileService.ts +542 -0
  282. package/src/services/GitHubAuthService.ts +240 -0
  283. package/src/testeranto.ts +62 -140
  284. package/src/utils/api.ts +15 -13
  285. package/src/utils/gitTest.ts +29 -0
  286. package/src/utils.ts +21 -12
  287. package/testeranto/App.css +94 -121
  288. package/testeranto/App.js +44601 -11225
  289. package/testeranto/bundles/golang/core/Calculator.golingvu.go +53 -0
  290. package/testeranto/bundles/golang/core/Calculator.golingvu.golingvu.go +53 -0
  291. package/testeranto/bundles/node/core/chunk-RIM6RECA.mjs +1170 -0
  292. package/testeranto/bundles/node/core/chunk-VXVF7WFO.mjs +4321 -0
  293. package/testeranto/bundles/node/core/example/Calculator.test.mjs +503 -0
  294. package/testeranto/bundles/node/core/src/lib/BaseSuite.test/node.test.mjs +94 -1231
  295. package/testeranto/bundles/node/core/src/lib/TipoSkripto.test/TipoSkripto.mjs +574 -0
  296. package/testeranto/bundles/node/core/src/lib/pmProxy.test/index.mjs +482 -0
  297. package/testeranto/bundles/pure/core/chunk-XYOCRDEQ.mjs +1080 -0
  298. package/testeranto/bundles/pure/core/src/Pure.test.mjs +410 -0
  299. package/testeranto/bundles/pure/core/src/lib/BaseSuite.test/pure.test.mjs +93 -1146
  300. package/testeranto/bundles/python/core/Calculator.pitono.test.py +24 -0
  301. package/testeranto/bundles/python/core/test_example.py +24 -0
  302. package/testeranto/bundles/web/core/MPLUSRounded1c-Black-O75GP5JI.ttf +0 -0
  303. package/testeranto/bundles/web/core/MPLUSRounded1c-Bold-R524Q5BH.ttf +0 -0
  304. package/testeranto/bundles/web/core/MPLUSRounded1c-ExtraBold-C6GRMYVT.ttf +0 -0
  305. package/testeranto/bundles/web/core/MPLUSRounded1c-Light-WKN65Y2C.ttf +0 -0
  306. package/testeranto/bundles/web/core/MPLUSRounded1c-Medium-ZC4DWL7C.ttf +0 -0
  307. package/testeranto/bundles/web/core/MPLUSRounded1c-Regular-DT6EKZ3S.ttf +0 -0
  308. package/testeranto/bundles/web/core/MPLUSRounded1c-Thin-YWDNVG6M.ttf +0 -0
  309. package/testeranto/bundles/web/core/chunk-DFRN4SYZ.mjs +2297 -0
  310. package/testeranto/bundles/web/core/chunk-JMDLMADH.mjs +27996 -0
  311. package/testeranto/bundles/web/core/chunk-LQMU5NCG.mjs +3082 -0
  312. package/testeranto/bundles/web/core/chunk-Q5TONB2Z.mjs +6874 -0
  313. package/testeranto/bundles/web/core/src/components/pure/FeaturesReporterView.test/index.mjs +164 -0
  314. package/testeranto/bundles/web/core/src/components/pure/ModalContent.test/index.css +11697 -0
  315. package/testeranto/bundles/web/core/src/components/pure/ModalContent.test/index.mjs +336 -0
  316. package/testeranto/bundles/web/core/src/components/pure/ProjectPageView.test/index.css +11697 -0
  317. package/testeranto/bundles/web/core/src/components/pure/ProjectPageView.test/index.mjs +517 -0
  318. package/testeranto/bundles/web/core/src/lib/BaseSuite.test/web.test.mjs +107 -1134
  319. package/testeranto/metafiles/golang/core.json +3 -3
  320. package/testeranto/metafiles/node/core.json +474 -31
  321. package/testeranto/metafiles/pure/core.json +144 -28
  322. package/testeranto/metafiles/python/core.json +11 -0
  323. package/testeranto/metafiles/web/core.json +15829 -45
  324. package/testeranto/reports/core/config.json +40 -0
  325. package/testeranto/reports/core/src/Pure.test/pure/exit.log +0 -0
  326. package/testeranto/reports/core/src/Pure.test/pure/lint_errors.txt +0 -0
  327. package/testeranto/reports/core/src/Pure.test/pure/prompt.txt +14 -0
  328. package/testeranto/reports/core/src/Pure.test/pure/type_errors.txt +73 -0
  329. package/testeranto/reports/core/src/components/pure/FeaturesReporterView.test/index/web/debug.log +0 -0
  330. package/testeranto/reports/core/src/components/pure/FeaturesReporterView.test/index/web/error.log +91 -0
  331. package/testeranto/reports/core/src/components/pure/FeaturesReporterView.test/index/web/exit.log +1 -0
  332. package/testeranto/reports/core/src/components/pure/FeaturesReporterView.test/index/web/info.log +2 -0
  333. package/testeranto/reports/core/src/components/pure/FeaturesReporterView.test/index/web/tests.json +68 -0
  334. package/testeranto/reports/core/src/components/pure/FeaturesReporterView.test/index/web/warn.log +0 -0
  335. package/testeranto/reports/core/src/components/pure/ProjectPageView.test/index/web/debug.log +0 -0
  336. package/testeranto/reports/core/src/components/pure/ProjectPageView.test/index/web/error.log +30 -0
  337. package/testeranto/reports/core/src/components/pure/ProjectPageView.test/index/web/exit.log +1 -0
  338. package/testeranto/reports/core/src/components/pure/ProjectPageView.test/index/web/info.log +2 -0
  339. package/testeranto/reports/core/src/components/pure/ProjectPageView.test/index/web/tests.json +88 -0
  340. package/testeranto/reports/core/src/components/pure/ProjectPageView.test/index/web/warn.log +0 -0
  341. package/testeranto/reports/core/src/lib/BaseSuite.test/node.test/node/lint_errors.txt +0 -6
  342. package/testeranto/reports/core/src/lib/BaseSuite.test/node.test/node/prompt.txt +0 -11
  343. package/testeranto/reports/core/src/lib/BaseSuite.test/node.test/node/stdout.log +1 -0
  344. package/testeranto/reports/core/src/lib/BaseSuite.test/node.test/node/tests.json +1 -1
  345. package/testeranto/reports/core/src/lib/BaseSuite.test/node.test/node/type_errors.txt +35 -38
  346. package/testeranto/reports/core/src/lib/BaseSuite.test/pure.test/pure/lint_errors.txt +0 -2
  347. package/testeranto/reports/core/src/lib/BaseSuite.test/pure.test/pure/prompt.txt +0 -10
  348. package/testeranto/reports/core/src/lib/BaseSuite.test/pure.test/pure/type_errors.txt +40 -38
  349. package/testeranto/reports/core/src/lib/BaseSuite.test/web.test/web/tests.json +1 -1
  350. package/testeranto/reports/core/src/lib/TipoSkripto.test/TipoSkripto/node/exit.log +1 -0
  351. package/testeranto/reports/core/src/lib/TipoSkripto.test/TipoSkripto/node/lint_errors.txt +0 -0
  352. package/testeranto/reports/core/src/lib/TipoSkripto.test/TipoSkripto/node/message.txt +17 -0
  353. package/testeranto/reports/core/src/lib/TipoSkripto.test/TipoSkripto/node/prompt.txt +17 -0
  354. package/testeranto/reports/core/src/lib/TipoSkripto.test/TipoSkripto/node/stderr.log +55 -0
  355. package/testeranto/reports/core/src/lib/TipoSkripto.test/TipoSkripto/node/stdout.log +191 -0
  356. package/testeranto/reports/core/src/lib/TipoSkripto.test/TipoSkripto/node/type_errors.txt +71 -0
  357. package/testeranto/reports/core/src/lib/pmProxy.test/index/node/exit.log +1 -0
  358. package/testeranto/reports/core/src/lib/pmProxy.test/index/node/lint_errors.txt +15 -0
  359. package/testeranto/reports/core/src/lib/pmProxy.test/index/node/message.txt +17 -0
  360. package/testeranto/reports/core/src/lib/pmProxy.test/index/node/prompt.txt +17 -0
  361. package/testeranto/reports/core/src/lib/pmProxy.test/index/node/stderr.log +20 -0
  362. package/testeranto/reports/core/src/lib/pmProxy.test/index/node/stdout.log +4 -0
  363. package/testeranto/reports/core/src/lib/pmProxy.test/index/node/type_errors.txt +49 -0
  364. package/testeranto/reports/core/summary.json +34 -6
  365. package/testeranto.config.ts +26 -20
  366. package/tsc.log +141 -91
  367. package/tsconfig.json +6 -2
  368. package/dist/types/design-editor/server.d.ts +0 -1
  369. package/testeranto/bundles/web/core/src/lib/BaseSuite.test/web.test.html +0 -15
  370. package/testeranto/reports/core/src/lib/BaseSuite.test/web.test/web/lint_errors.txt +0 -2
  371. package/testeranto/reports/core/src/lib/BaseSuite.test/web.test/web/prompt.txt +0 -25
  372. package/testeranto/reports/core/src/lib/BaseSuite.test/web.test/web/type_errors.txt +0 -56
  373. /package/testeranto/reports/core/src/{lib/BaseSuite.test/web.test/web → Pure.test/pure}/message.txt +0 -0
@@ -5,1771 +5,628 @@
5
5
  import { spawn } from "node:child_process";
6
6
  import ansiColors from "ansi-colors";
7
7
  import net from "net";
8
- import fs, { watch } from "fs";
9
- import path from "path";
10
- import puppeteer from "puppeteer-core";
8
+ import fs from "fs";
11
9
  import ansiC from "ansi-colors";
12
- import crypto from "node:crypto";
13
- import { WebSocketServer } from "ws";
14
- import http from "http";
15
- import url from "url";
16
- import mime from "mime-types";
17
- import { getRunnables } from "../utils";
10
+ import { webEvaluator } from "../utils";
18
11
  import { Queue } from "../utils/queue.js";
19
- import { PM_WithEslintAndTsc } from "./PM_WithEslintAndTsc.js";
20
- const changes = {};
21
- const fileHashes = {};
12
+ import { createLogStreams, statusMessagePretty } from "./utils.js";
13
+ import { PM_WithProcesses } from "./PM_WithProcesses.js";
22
14
  const files = {};
23
15
  const screenshots = {};
24
- function runtimeLogs(runtime, reportDest) {
25
- const safeDest = reportDest || `testeranto/reports/default_${Date.now()}`;
26
- try {
27
- if (!fs.existsSync(safeDest)) {
28
- fs.mkdirSync(safeDest, { recursive: true });
29
- }
30
- if (runtime === "node") {
31
- return {
32
- stdout: fs.createWriteStream(`${safeDest}/stdout.log`),
33
- stderr: fs.createWriteStream(`${safeDest}/stderr.log`),
34
- exit: fs.createWriteStream(`${safeDest}/exit.log`),
35
- };
36
- }
37
- else if (runtime === "web") {
38
- return {
39
- info: fs.createWriteStream(`${safeDest}/info.log`),
40
- warn: fs.createWriteStream(`${safeDest}/warn.log`),
41
- error: fs.createWriteStream(`${safeDest}/error.log`),
42
- debug: fs.createWriteStream(`${safeDest}/debug.log`),
43
- exit: fs.createWriteStream(`${safeDest}/exit.log`),
44
- };
45
- }
46
- else if (runtime === "pure") {
47
- return {
48
- exit: fs.createWriteStream(`${safeDest}/exit.log`),
49
- };
50
- }
51
- else if (runtime === "pitono") {
52
- return {
53
- stdout: fs.createWriteStream(`${safeDest}/stdout.log`),
54
- stderr: fs.createWriteStream(`${safeDest}/stderr.log`),
55
- exit: fs.createWriteStream(`${safeDest}/exit.log`),
56
- };
57
- }
58
- else {
59
- throw `unknown runtime: ${runtime}`;
60
- }
61
- }
62
- catch (e) {
63
- console.error(`Failed to create log streams in ${safeDest}:`, e);
64
- throw e;
65
- }
66
- }
67
- function createLogStreams(reportDest, runtime) {
68
- // Create directory if it doesn't exist
69
- if (!fs.existsSync(reportDest)) {
70
- fs.mkdirSync(reportDest, { recursive: true });
71
- }
72
- const streams = runtimeLogs(runtime, reportDest);
73
- // const streams = {
74
- // exit: fs.createWriteStream(`${reportDest}/exit.log`),
75
- const safeDest = reportDest || `testeranto/reports/default_${Date.now()}`;
76
- try {
77
- if (!fs.existsSync(safeDest)) {
78
- fs.mkdirSync(safeDest, { recursive: true });
79
- }
80
- const streams = runtimeLogs(runtime, safeDest);
81
- // const streams = {
82
- // exit: fs.createWriteStream(`${safeDest}/exit.log`),
83
- // ...(runtime === "node" || runtime === "pure"
84
- // ? {
85
- // stdout: fs.createWriteStream(`${safeDest}/stdout.log`),
86
- // stderr: fs.createWriteStream(`${safeDest}/stderr.log`),
87
- // }
88
- // : {
89
- // info: fs.createWriteStream(`${safeDest}/info.log`),
90
- // warn: fs.createWriteStream(`${safeDest}/warn.log`),
91
- // error: fs.createWriteStream(`${safeDest}/error.log`),
92
- // debug: fs.createWriteStream(`${safeDest}/debug.log`),
93
- // }),
94
- // };
95
- return Object.assign(Object.assign({}, streams), { closeAll: () => {
96
- Object.values(streams).forEach((stream) => !stream.closed && stream.close());
97
- }, writeExitCode: (code, error) => {
98
- if (error) {
99
- streams.exit.write(`Error: ${error.message}\n`);
100
- if (error.stack) {
101
- streams.exit.write(`Stack Trace:\n${error.stack}\n`);
102
- }
103
- }
104
- streams.exit.write(`${code}\n`);
105
- }, exit: streams.exit });
106
- }
107
- catch (e) {
108
- console.error(`Failed to create log streams in ${safeDest}:`, e);
109
- throw e;
110
- }
111
- }
112
- async function fileHash(filePath, algorithm = "md5") {
113
- return new Promise((resolve, reject) => {
114
- const hash = crypto.createHash(algorithm);
115
- const fileStream = fs.createReadStream(filePath);
116
- fileStream.on("data", (data) => {
117
- hash.update(data);
118
- });
119
- fileStream.on("end", () => {
120
- const fileHash = hash.digest("hex");
121
- resolve(fileHash);
122
- });
123
- fileStream.on("error", (error) => {
124
- reject(`Error reading file: ${error.message}`);
125
- });
126
- });
127
- }
128
- const statusMessagePretty = (failures, test, runtime) => {
129
- if (failures === 0) {
130
- console.log(ansiC.green(ansiC.inverse(`${runtime} > ${test}`)));
131
- }
132
- else if (failures > 0) {
133
- console.log(ansiC.red(ansiC.inverse(`${runtime} > ${test} failed ${failures} times (exit code: ${failures})`)));
134
- }
135
- else {
136
- console.log(ansiC.red(ansiC.inverse(`${runtime} > ${test} crashed (exit code: -1)`)));
137
- }
138
- };
139
- async function writeFileAndCreateDir(filePath, data) {
140
- const dirPath = path.dirname(filePath);
141
- try {
142
- await fs.promises.mkdir(dirPath, { recursive: true });
143
- await fs.writeFileSync(filePath, data);
144
- }
145
- catch (error) {
146
- console.error(`Error writing file: ${error}`);
147
- }
148
- }
149
- const filesHash = async (files, algorithm = "md5") => {
150
- return new Promise((resolve, reject) => {
151
- resolve(files.reduce(async (mm, f) => {
152
- return (await mm) + (await fileHash(f));
153
- }, Promise.resolve("")));
154
- });
155
- };
156
- function isValidUrl(string) {
157
- try {
158
- new URL(string);
159
- return true;
160
- }
161
- catch (err) {
162
- return false;
163
- }
164
- }
165
- // Wait for file to exist, checks every 2 seconds by default
166
- async function pollForFile(path, timeout = 2000) {
167
- const intervalObj = setInterval(function () {
168
- const file = path;
169
- const fileExists = fs.existsSync(file);
170
- if (fileExists) {
171
- clearInterval(intervalObj);
172
- }
173
- }, timeout);
174
- }
175
- export class PM_Main extends PM_WithEslintAndTsc {
176
- constructor(configs, name, mode) {
177
- super(configs, name, mode);
178
- this.logStreams = {};
179
- this.sidecars = {};
180
- this.clients = new Set();
181
- this.runningProcesses = new Map();
182
- this.allProcesses = new Map();
183
- this.processLogs = new Map();
184
- this.getRunnables = (tests, testName, payload = {
185
- nodeEntryPoints: {},
186
- nodeEntryPointSidecars: {},
187
- webEntryPoints: {},
188
- webEntryPointSidecars: {},
189
- pureEntryPoints: {},
190
- pureEntryPointSidecars: {},
191
- }) => {
192
- return getRunnables(tests, testName, payload);
193
- };
16
+ export class PM_Main extends PM_WithProcesses {
17
+ constructor() {
18
+ super(...arguments);
194
19
  this.launchPure = async (src, dest) => {
195
- console.log(ansiC.green(ansiC.inverse(`pure < ${src}`)));
196
- this.bddTestIsRunning(src);
197
- const reportDest = `testeranto/reports/${this.name}/${src
198
- .split(".")
199
- .slice(0, -1)
200
- .join(".")}/pure`;
201
- if (!fs.existsSync(reportDest)) {
202
- fs.mkdirSync(reportDest, { recursive: true });
203
- }
204
- const destFolder = dest.replace(".mjs", "");
205
- let argz = "";
206
- const testConfig = this.configs.tests.find((t) => {
207
- return t[0] === src;
208
- });
209
- if (!testConfig) {
210
- console.log(ansiC.inverse("missing test config! Exiting ungracefully!"));
211
- process.exit(-1);
212
- }
213
- const testConfigResource = testConfig[2];
214
- const portsToUse = [];
215
- if (testConfigResource.ports === 0) {
216
- argz = JSON.stringify({
217
- scheduled: true,
218
- name: src,
219
- ports: portsToUse,
220
- fs: reportDest,
221
- browserWSEndpoint: this.browser.wsEndpoint(),
20
+ const processId = `pure-${src}-${Date.now()}`;
21
+ const command = `pure test: ${src}`;
22
+ // Create the promise
23
+ const purePromise = (async () => {
24
+ this.bddTestIsRunning(src);
25
+ const reportDest = `testeranto/reports/${this.name}/${src
26
+ .split(".")
27
+ .slice(0, -1)
28
+ .join(".")}/pure`;
29
+ if (!fs.existsSync(reportDest)) {
30
+ fs.mkdirSync(reportDest, { recursive: true });
31
+ }
32
+ const destFolder = dest.replace(".mjs", "");
33
+ let argz = "";
34
+ const testConfig = this.configs.tests.find((t) => {
35
+ return t[0] === src;
222
36
  });
223
- }
224
- else if (testConfigResource.ports > 0) {
225
- const openPorts = Object.entries(this.ports).filter(([portnumber, status]) => status === "");
226
- if (openPorts.length >= testConfigResource.ports) {
227
- for (let i = 0; i < testConfigResource.ports; i++) {
228
- portsToUse.push(openPorts[i][0]);
229
- this.ports[openPorts[i][0]] = src; // port is now claimed
230
- }
37
+ if (!testConfig) {
38
+ console.log(ansiC.inverse("missing test config! Exiting ungracefully!"));
39
+ process.exit(-1);
40
+ }
41
+ const testConfigResource = testConfig[2];
42
+ const portsToUse = [];
43
+ if (testConfigResource.ports === 0) {
231
44
  argz = JSON.stringify({
232
45
  scheduled: true,
233
46
  name: src,
234
47
  ports: portsToUse,
235
- fs: destFolder,
48
+ fs: reportDest,
236
49
  browserWSEndpoint: this.browser.wsEndpoint(),
237
50
  });
238
51
  }
52
+ else if (testConfigResource.ports > 0) {
53
+ const openPorts = Object.entries(this.ports).filter(([portnumber, status]) => status === "");
54
+ if (openPorts.length >= testConfigResource.ports) {
55
+ for (let i = 0; i < testConfigResource.ports; i++) {
56
+ portsToUse.push(openPorts[i][0]);
57
+ this.ports[openPorts[i][0]] = src; // port is now claimed
58
+ }
59
+ argz = JSON.stringify({
60
+ scheduled: true,
61
+ name: src,
62
+ ports: portsToUse,
63
+ fs: destFolder,
64
+ browserWSEndpoint: this.browser.wsEndpoint(),
65
+ });
66
+ }
67
+ else {
68
+ this.queue.push(src);
69
+ return [Math.random(), argz];
70
+ }
71
+ }
239
72
  else {
240
- this.queue.push(src);
241
- return [Math.random(), argz];
73
+ console.error("negative port makes no sense", src);
74
+ process.exit(-1);
242
75
  }
243
- }
244
- else {
245
- console.error("negative port makes no sense", src);
246
- process.exit(-1);
247
- }
248
- const builtfile = dest;
249
- // const webSideCares: Page[] = [];
250
- // fs.writeFileSync(
251
- // `${reportDest}/stdlog.txt`,
252
- // "THIS FILE IS AUTO GENERATED. IT IS PURPOSEFULLY LEFT BLANK."
253
- // );
254
- // await Promise.all(
255
- // testConfig[3].map(async (sidecar) => {
256
- // if (sidecar[1] === "web") {
257
- // const s = await this.launchWebSideCar(
258
- // sidecar[0],
259
- // destinationOfRuntime(sidecar[0], "web", this.configs),
260
- // sidecar
261
- // );
262
- // webSideCares.push(s);
263
- // return s;
264
- // }
265
- // if (sidecar[1] === "node") {
266
- // return this.launchNodeSideCar(
267
- // sidecar[0],
268
- // destinationOfRuntime(sidecar[0], "node", this.configs),
269
- // sidecar
270
- // );
271
- // }
272
- // })
273
- // );
274
- const logs = createLogStreams(reportDest, "pure");
275
- try {
276
- await import(`${builtfile}?cacheBust=${Date.now()}`).then((module) => {
277
- // Override console methods to redirect logs
278
- // Only override stdout/stderr methods for pure runtime
279
- const originalConsole = Object.assign({}, console);
280
- // console.log = (...args) => {
281
- // logs.stdout.write(args.join(" ") + "\n");
282
- // originalConsole.log(...args);
283
- // };
284
- // console.error = (...args) => {
285
- // logs.stderr.write(args.join(" ") + "\n");
286
- // originalConsole.error(...args);
287
- // };
288
- return module.default
289
- .then((defaultModule) => {
290
- defaultModule
291
- .receiveTestResourceConfig(argz)
292
- .then(async (results) => {
293
- // this.receiveFeatures(results.features, destFolder, src, "pure");
294
- // this.receiveFeaturesV2(reportDest, src, "pure");
295
- statusMessagePretty(results.fails, src, "pure");
296
- this.bddTestIsNowDone(src, results.fails);
76
+ const builtfile = dest;
77
+ const logs = createLogStreams(reportDest, "pure");
78
+ try {
79
+ await import(`${builtfile}?cacheBust=${Date.now()}`).then((module) => {
80
+ return module.default
81
+ .then((defaultModule) => {
82
+ return defaultModule
83
+ .receiveTestResourceConfig(argz)
84
+ .then(async (results) => {
85
+ statusMessagePretty(results.fails, src, "pure");
86
+ this.bddTestIsNowDone(src, results.fails);
87
+ return results.fails;
88
+ });
297
89
  })
298
- .catch((e1) => {
299
- console.log(ansiC.red(`launchPure - ${src} errored with: ${e1.stack}`));
90
+ .catch((e2) => {
91
+ console.log(ansiColors.red(`pure ! ${src} failed to execute. No "tests.json" file was generated. Check the logs for more info`));
92
+ logs.exit.write(e2.stack);
93
+ logs.exit.write(-1);
300
94
  this.bddTestIsNowDone(src, -1);
301
95
  statusMessagePretty(-1, src, "pure");
96
+ throw e2;
302
97
  });
303
- // .finally(() => {
304
- // // webSideCares.forEach((webSideCar) => webSideCar.close());
305
- // });
306
- })
307
- .catch((e2) => {
308
- console.log(ansiColors.red(`pure ! ${src} failed to execute. No "tests.json" file was generated. Check the logs for more info`));
309
- logs.exit.write(e2.stack);
310
- logs.exit.write(-1);
311
- this.bddTestIsNowDone(src, -1);
312
- statusMessagePretty(-1, src, "pure");
313
- // console.error(e);
314
- })
315
- .finally((x) => {
316
- // const fileSet = files[src] || new Set();
317
- // fs.writeFileSync(
318
- // reportDest + "/manifest.json",
319
- // JSON.stringify(Array.from(fileSet))
320
- // );
321
98
  });
322
- });
323
- }
324
- catch (e3) {
325
- logs.writeExitCode(-1, e3);
326
- console.log(ansiC.red(ansiC.inverse(`${src} 1 errored with: ${e3}. Check logs for more info`)));
327
- logs.exit.write(e3.stack);
328
- logs.exit.write("-1");
329
- this.bddTestIsNowDone(src, -1);
330
- statusMessagePretty(-1, src, "pure");
331
- }
332
- for (let i = 0; i <= portsToUse.length; i++) {
333
- if (portsToUse[i]) {
334
- this.ports[portsToUse[i]] = ""; //port is open again
335
99
  }
336
- }
100
+ catch (e3) {
101
+ logs.writeExitCode(-1, e3);
102
+ console.log(ansiC.red(ansiC.inverse(`${src} 1 errored with: ${e3}. Check logs for more info`)));
103
+ logs.exit.write(e3.stack);
104
+ logs.exit.write("-1");
105
+ this.bddTestIsNowDone(src, -1);
106
+ statusMessagePretty(-1, src, "pure");
107
+ throw e3;
108
+ }
109
+ finally {
110
+ for (let i = 0; i <= portsToUse.length; i++) {
111
+ if (portsToUse[i]) {
112
+ this.ports[portsToUse[i]] = ""; // port is open again
113
+ }
114
+ }
115
+ }
116
+ })();
117
+ // Add to process manager
118
+ this.addPromiseProcess(processId, purePromise, command, "bdd-test", src, "pure");
337
119
  };
338
120
  this.launchNode = async (src, dest) => {
339
- console.log(ansiC.green(ansiC.inverse(`node < ${src}`)));
340
- this.bddTestIsRunning(src);
341
- const reportDest = `testeranto/reports/${this.name}/${src
342
- .split(".")
343
- .slice(0, -1)
344
- .join(".")}/node`;
345
- if (!fs.existsSync(reportDest)) {
346
- fs.mkdirSync(reportDest, { recursive: true });
347
- }
348
- // const destFolder = dest.replace(".mjs", "");
349
- let testResources = "";
350
- const testConfig = this.configs.tests.find((t) => {
351
- return t[0] === src;
352
- });
353
- if (!testConfig) {
354
- console.log(ansiC.inverse(`missing test config! Exiting ungracefully for '${src}'`));
355
- process.exit(-1);
356
- }
357
- const testConfigResource = testConfig[2];
358
- const portsToUse = [];
359
- if (testConfigResource.ports === 0) {
360
- const t = {
361
- name: src,
362
- // ports: portsToUse.map((v) => Number(v)),
363
- ports: [],
364
- fs: reportDest,
365
- browserWSEndpoint: this.browser.wsEndpoint(),
366
- };
367
- testResources = JSON.stringify(t);
368
- }
369
- else if (testConfigResource.ports > 0) {
370
- const openPorts = Object.entries(this.ports).filter(([portnumber, portopen]) => portopen === "");
371
- if (openPorts.length >= testConfigResource.ports) {
372
- for (let i = 0; i < testConfigResource.ports; i++) {
373
- portsToUse.push(openPorts[i][0]); // Convert string port to number
374
- this.ports[openPorts[i][0]] = src; // port is now claimed
375
- }
376
- testResources = JSON.stringify({
377
- scheduled: true,
121
+ const processId = `node-${src}-${Date.now()}`;
122
+ const command = `node test: ${src}`;
123
+ // Create the promise
124
+ const nodePromise = (async () => {
125
+ this.bddTestIsRunning(src);
126
+ const reportDest = `testeranto/reports/${this.name}/${src
127
+ .split(".")
128
+ .slice(0, -1)
129
+ .join(".")}/node`;
130
+ if (!fs.existsSync(reportDest)) {
131
+ fs.mkdirSync(reportDest, { recursive: true });
132
+ }
133
+ let testResources = "";
134
+ const testConfig = this.configs.tests.find((t) => {
135
+ return t[0] === src;
136
+ });
137
+ if (!testConfig) {
138
+ console.log(ansiC.inverse(`missing test config! Exiting ungracefully for '${src}'`));
139
+ process.exit(-1);
140
+ }
141
+ const testConfigResource = testConfig[2];
142
+ const portsToUse = [];
143
+ if (testConfigResource.ports === 0) {
144
+ const t = {
378
145
  name: src,
379
- ports: portsToUse,
146
+ ports: [],
380
147
  fs: reportDest,
381
148
  browserWSEndpoint: this.browser.wsEndpoint(),
382
- });
383
- }
384
- else {
385
- console.log(ansiC.red(`node: cannot run ${src} because there are no open ports ATM. This job will be enqueued and run again run a port is available`));
386
- this.queue.push(src);
387
- return [Math.random(), argz]; // Add this return
149
+ };
150
+ testResources = JSON.stringify(t);
388
151
  }
389
- }
390
- else {
391
- console.error("negative port makes no sense", src);
392
- process.exit(-1);
393
- }
394
- const builtfile = dest;
395
- let haltReturns = false;
396
- const ipcfile = "/tmp/tpipe_" + Math.random();
397
- const child = spawn("node",
398
- // "node",
399
- [
400
- // "--inspect-brk",
401
- builtfile,
402
- testResources,
403
- ipcfile,
404
- ], {
405
- stdio: ["pipe", "pipe", "pipe", "ipc"],
406
- });
407
- let buffer = new Buffer("");
408
- const server = net.createServer((socket) => {
409
- const queue = new Queue();
410
- socket.on("data", (data) => {
411
- buffer = Buffer.concat([buffer, data]);
412
- for (let b = 0; b < buffer.length + 1; b++) {
413
- const c = buffer.slice(0, b);
414
- let d;
415
- try {
416
- d = JSON.parse(c.toString());
417
- queue.enqueue(d);
418
- buffer = buffer.slice(b, buffer.length + 1);
419
- b = 0;
420
- }
421
- catch (e) {
422
- // b++;
152
+ else if (testConfigResource.ports > 0) {
153
+ const openPorts = Object.entries(this.ports).filter(([portnumber, portopen]) => portopen === "");
154
+ if (openPorts.length >= testConfigResource.ports) {
155
+ for (let i = 0; i < testConfigResource.ports; i++) {
156
+ portsToUse.push(openPorts[i][0]);
157
+ this.ports[openPorts[i][0]] = src; // port is now claimed
423
158
  }
424
- }
425
- while (queue.size() > 0) {
426
- const message = queue.dequeue();
427
- if (message) {
428
- // set up the "node" listeners
429
- this.mapping().forEach(async ([command, func]) => {
430
- if (message[0] === command) {
431
- const x = message.slice(1, -1);
432
- const r = await this[command](...x);
433
- if (!haltReturns) {
434
- child.send(JSON.stringify({
435
- payload: r,
436
- key: message[message.length - 1],
437
- }));
438
- }
439
- }
440
- });
441
- }
442
- }
443
- });
444
- });
445
- const logs = createLogStreams(reportDest, "node");
446
- server.listen(ipcfile, () => {
447
- var _a, _b;
448
- // Only handle stdout/stderr for node runtime
449
- (_a = child.stdout) === null || _a === void 0 ? void 0 : _a.on("data", (data) => {
450
- var _a;
451
- (_a = logs.stdout) === null || _a === void 0 ? void 0 : _a.write(data); // Add null check
452
- });
453
- (_b = child.stderr) === null || _b === void 0 ? void 0 : _b.on("data", (data) => {
454
- var _a;
455
- (_a = logs.stderr) === null || _a === void 0 ? void 0 : _a.write(data); // Add null check
456
- });
457
- child.on("error", (err) => { });
458
- child.on("close", (code) => {
459
- const exitCode = code === null ? -1 : code;
460
- if (exitCode < 0) {
461
- logs.writeExitCode(exitCode, new Error("Process crashed or was terminated"));
462
- }
463
- else {
464
- logs.writeExitCode(exitCode);
465
- }
466
- logs.closeAll();
467
- server.close();
468
- if (!files[src]) {
469
- files[src] = new Set();
470
- }
471
- if (exitCode === 255) {
472
- console.log(ansiColors.red(`node ! ${src} failed to execute. No "tests.json" file was generated. Check ${reportDest}/stderr.log for more info`));
473
- this.bddTestIsNowDone(src, -1);
474
- statusMessagePretty(-1, src, "node");
475
- return;
476
- }
477
- else if (exitCode === 0) {
478
- this.bddTestIsNowDone(src, 0);
479
- statusMessagePretty(0, src, "node");
159
+ testResources = JSON.stringify({
160
+ scheduled: true,
161
+ name: src,
162
+ ports: portsToUse,
163
+ fs: reportDest,
164
+ browserWSEndpoint: this.browser.wsEndpoint(),
165
+ });
480
166
  }
481
167
  else {
482
- this.bddTestIsNowDone(src, exitCode);
483
- statusMessagePretty(exitCode, src, "node");
484
- }
485
- haltReturns = true;
486
- });
487
- child.on("exit", (code) => {
488
- haltReturns = true;
489
- for (let i = 0; i <= portsToUse.length; i++) {
490
- if (portsToUse[i]) {
491
- this.ports[portsToUse[i]] = ""; //port is open again
492
- }
168
+ console.log(ansiC.red(`node: cannot run ${src} because there are no open ports ATM. This job will be enqueued and run again run a port is available`));
169
+ this.queue.push(src);
170
+ return [Math.random(), testResources];
493
171
  }
172
+ }
173
+ else {
174
+ console.error("negative port makes no sense", src);
175
+ process.exit(-1);
176
+ }
177
+ const builtfile = dest;
178
+ let haltReturns = false;
179
+ const ipcfile = "/tmp/tpipe_" + Math.random();
180
+ const child = spawn("node", [builtfile, testResources, ipcfile], {
181
+ stdio: ["pipe", "pipe", "pipe", "ipc"],
494
182
  });
495
- child.on("error", (e) => {
496
- console.log("error");
497
- haltReturns = true;
498
- console.log(ansiC.red(ansiC.inverse(`${src} errored with: ${e.name}. Check error logs for more info`)));
499
- this.bddTestIsNowDone(src, -1);
500
- statusMessagePretty(-1, src, "node");
501
- });
502
- });
503
- };
504
- this.launchWebSideCar = async (testConfig) => {
505
- const src = testConfig[0];
506
- const dest = src.split(".").slice(0, -1).join(".");
507
- // const d = dest + ".mjs";
508
- const destFolder = dest.replace(".mjs", "");
509
- console.log(ansiC.green(ansiC.inverse(`launchWebSideCar ${src}`)));
510
- // const fileStreams2: fs.WriteStream[] = [];
511
- // const doneFileStream2: Promise<any>[] = [];
512
- const logs = createLogStreams(dest, "web");
513
- return new Promise((res, rej) => {
514
- this.browser
515
- .newPage()
516
- .then(async (page) => {
517
- this.mapping().forEach(async ([command, func]) => {
518
- page.exposeFunction(command, func);
519
- });
520
- const close = () => {
521
- if (!files[src]) {
522
- files[src] = new Set();
523
- }
524
- // files[src].add(filepath);
525
- // fs.writeFileSync(
526
- // destFolder + "/manifest.json",
527
- // JSON.stringify(Array.from(files[src]))
528
- // );
529
- delete files[src];
530
- Promise.all(screenshots[src] || []).then(() => {
531
- delete screenshots[src];
532
- page.close();
533
- });
534
- };
535
- page.on("pageerror", (err) => {
536
- console.debug(`Error from ${src}: [${err.name}] `);
537
- console.debug(`Error from ${src}: [${err.name}] `);
538
- if (err.cause) {
539
- console.debug(`Error from ${src} cause: [${err.cause}] `);
540
- }
541
- if (err.stack) {
542
- console.debug(`Error from stack ${src}: [${err.stack}] `);
543
- }
544
- console.debug(`Error from message ${src}: [${err.message}] `);
545
- this.bddTestIsNowDone(src, -1);
546
- close();
547
- });
548
- page.on("console", (log) => {
549
- var _a, _b, _c, _d;
550
- const msg = `${log.text()}\n${JSON.stringify(log.location())}\n${JSON.stringify(log.stackTrace())}\n`;
551
- switch (log.type()) {
552
- case "info":
553
- (_a = logs.info) === null || _a === void 0 ? void 0 : _a.write(msg);
554
- break;
555
- case "warn":
556
- (_b = logs.warn) === null || _b === void 0 ? void 0 : _b.write(msg);
557
- break;
558
- case "error":
559
- (_c = logs.error) === null || _c === void 0 ? void 0 : _c.write(msg);
560
- break;
561
- case "debug":
562
- (_d = logs.debug) === null || _d === void 0 ? void 0 : _d.write(msg);
563
- break;
564
- default:
565
- break;
566
- }
567
- });
568
- await page.goto(`file://${`${destFolder}.html`}`, {});
569
- const webArgz = JSON.stringify({
570
- name: dest,
571
- ports: [].toString(),
572
- fs: dest,
573
- browserWSEndpoint: this.browser.wsEndpoint(),
574
- });
575
- const d = `${dest}?cacheBust=${Date.now()}`;
576
- const evaluation = `
577
- import('${d}').then(async (x) => {
578
-
579
- try {
580
- return await (await x.default).receiveTestResourceConfig(${webArgz})
581
- } catch (e) {
582
- console.log("fail", e.toString())
583
- }
584
- })`;
585
- await page
586
- .evaluate(evaluation)
587
- .then(async ({ fails, failed, features }) => {
588
- // this.receiveFeatures(features, destFolder, src, "web");
589
- // this.receiveFeaturesV2(reportDest, src, "web");
590
- statusMessagePretty(fails, src, "web");
591
- this.bddTestIsNowDone(src, fails);
592
- })
593
- .catch((e) => {
594
- console.log(ansiC.red(ansiC.inverse(`launchWebSidecar - ${src} errored with: ${e}`)));
595
- })
596
- .finally(() => {
597
- this.bddTestIsNowDone(src, -1);
598
- close();
599
- });
600
- return page;
601
- // return page;
602
- })
603
- .then(async (page) => {
604
- await page.goto(`file://${`${dest}.html`}`, {});
605
- res([Math.random(), page]);
606
- });
607
- });
608
- };
609
- this.launchNodeSideCar = async (sidecar) => {
610
- const src = sidecar[0];
611
- const dest = process.cwd() + `/testeranto/bundles/node/${this.name}/${sidecar[0]}`;
612
- const d = dest + ".mjs";
613
- console.log(ansiC.green(ansiC.inverse(`launchNodeSideCar ${sidecar[0]}`)));
614
- const destFolder = dest.replace(".ts", "");
615
- const reportDest = `testeranto/reports/${this.name}/${src
616
- .split(".")
617
- .slice(0, -1)
618
- .join(".")}/node`;
619
- const argz = {
620
- name: sidecar[0],
621
- ports: [],
622
- fs: destFolder,
623
- browserWSEndpoint: this.browser.wsEndpoint(),
624
- };
625
- const testReq = sidecar[2];
626
- const logs = createLogStreams(dest, "node");
627
- const portsToUse = [];
628
- if (testReq.ports === 0) {
629
- // argz = {
630
- // name: sidecar[0],
631
- // ports: portsToUse,
632
- // fs: destFolder,
633
- // browserWSEndpoint: this.browser.wsEndpoint(),
634
- // };
635
- }
636
- else if (testReq.ports > 0) {
637
- const openPorts = Object.entries(this.ports).filter(([portnumber, portopen]) => portopen === "");
638
- if (openPorts.length >= testReq.ports) {
639
- for (let i = 0; i < testReq.ports; i++) {
640
- portsToUse.push(Number(openPorts[i][0])); // Convert string port to number
641
- this.ports[openPorts[i][0]] = src; // port is now closed
642
- }
643
- argz.ports = portsToUse;
644
- const builtfile = destFolder + ".mjs";
645
- let haltReturns = false;
646
- let buffer = new Buffer("");
647
- const server = net.createServer((socket) => {
648
- socket.on("data", (data) => {
649
- buffer = Buffer.concat([buffer, data]);
650
- const messages = [];
651
- for (let b = 0; b < buffer.length + 1; b++) {
652
- const c = buffer.slice(0, b);
653
- let d;
654
- try {
655
- d = JSON.parse(c.toString());
656
- messages.push(d);
657
- buffer = buffer.slice(b, buffer.length + 1);
658
- b = 0;
659
- }
660
- catch (e) {
661
- // b++;
662
- }
183
+ let buffer = new Buffer("");
184
+ const server = net.createServer((socket) => {
185
+ const queue = new Queue();
186
+ socket.on("data", (data) => {
187
+ buffer = Buffer.concat([buffer, data]);
188
+ for (let b = 0; b < buffer.length + 1; b++) {
189
+ const c = buffer.slice(0, b);
190
+ let d;
191
+ try {
192
+ d = JSON.parse(c.toString());
193
+ queue.enqueue(d);
194
+ buffer = buffer.slice(b, buffer.length + 1);
195
+ b = 0;
663
196
  }
664
- messages.forEach(async (payload) => {
197
+ catch (e) {
198
+ // b++;
199
+ }
200
+ }
201
+ while (queue.size() > 0) {
202
+ const message = queue.dequeue();
203
+ if (message) {
204
+ // set up the "node" listeners
665
205
  this.mapping().forEach(async ([command, func]) => {
666
- if (payload[0] === command) {
667
- const x = payload.slice(1, -1);
206
+ if (message[0] === command) {
207
+ const x = message.slice(1, -1);
668
208
  const r = await this[command](...x);
669
209
  if (!haltReturns) {
670
210
  child.send(JSON.stringify({
671
211
  payload: r,
672
- key: payload[payload.length - 1],
212
+ key: message[message.length - 1],
673
213
  }));
674
214
  }
675
215
  }
676
216
  });
677
- });
678
- });
679
- });
680
- const child = spawn("node", [builtfile, JSON.stringify(argz)], {
681
- stdio: ["pipe", "pipe", "pipe", "ipc"],
682
- // silent: true
217
+ }
218
+ }
683
219
  });
684
- const p = "/tmp/tpipe" + Math.random();
685
- server.listen(p, () => {
220
+ });
221
+ const logs = createLogStreams(reportDest, "node");
222
+ return new Promise((resolve, reject) => {
223
+ server.listen(ipcfile, () => {
224
+ var _a, _b;
225
+ (_a = child.stdout) === null || _a === void 0 ? void 0 : _a.on("data", (data) => {
226
+ var _a;
227
+ (_a = logs.stdout) === null || _a === void 0 ? void 0 : _a.write(data);
228
+ });
229
+ (_b = child.stderr) === null || _b === void 0 ? void 0 : _b.on("data", (data) => {
230
+ var _a;
231
+ (_a = logs.stderr) === null || _a === void 0 ? void 0 : _a.write(data);
232
+ });
686
233
  child.on("close", (code) => {
234
+ const exitCode = code === null ? -1 : code;
235
+ if (exitCode < 0) {
236
+ logs.writeExitCode(exitCode, new Error("Process crashed or was terminated"));
237
+ }
238
+ else {
239
+ logs.writeExitCode(exitCode);
240
+ }
241
+ logs.closeAll();
687
242
  server.close();
688
- haltReturns = true;
689
- });
690
- child.on("exit", (code) => {
691
- haltReturns = true;
692
- for (let i = 0; i <= portsToUse.length; i++) {
693
- if (portsToUse[i]) {
694
- this.ports[portsToUse[i]] = ""; //port is open again
695
- }
243
+ if (exitCode === 255) {
244
+ console.log(ansiColors.red(`node ! ${src} failed to execute. No "tests.json" file was generated. Check ${reportDest}/stderr.log for more info`));
245
+ this.bddTestIsNowDone(src, -1);
246
+ statusMessagePretty(-1, src, "node");
247
+ reject(new Error(`Process exited with code ${exitCode}`));
248
+ }
249
+ else if (exitCode === 0) {
250
+ this.bddTestIsNowDone(src, 0);
251
+ statusMessagePretty(0, src, "node");
252
+ resolve();
696
253
  }
254
+ else {
255
+ this.bddTestIsNowDone(src, exitCode);
256
+ statusMessagePretty(exitCode, src, "node");
257
+ reject(new Error(`Process exited with code ${exitCode}`));
258
+ }
259
+ haltReturns = true;
697
260
  });
698
261
  child.on("error", (e) => {
699
- var _a;
700
- if (fs.existsSync(p)) {
701
- fs.rmSync(p);
702
- }
262
+ console.log("error");
703
263
  haltReturns = true;
704
- console.log(ansiC.red(ansiC.inverse(`launchNodeSideCar - ${src} errored with: ${e.name}. Check logs for more info`)));
705
- (_a = logs.error) === null || _a === void 0 ? void 0 : _a.write(e.toString() + "\n");
706
- // this.bddTestIsNowDone(src, -1);
707
- // statusMessagePretty(-1, src);
264
+ console.log(ansiC.red(ansiC.inverse(`${src} errored with: ${e.name}. Check error logs for more info`)));
265
+ this.bddTestIsNowDone(src, -1);
266
+ statusMessagePretty(-1, src, "node");
267
+ reject(e);
708
268
  });
709
269
  });
710
- child.send({ path: p });
711
- const r = Math.random();
712
- this.nodeSidecars[r] = child;
713
- return [r, argz];
714
- }
715
- else {
716
- console.log(ansiC.red(`cannot ${src} because there are no open ports. the job will be unqueued`));
717
- this.queue.push(sidecar[0]);
718
- return [Math.random(), argz];
719
- }
720
- }
721
- else {
722
- console.error("negative port makes no sense", sidecar[0]);
723
- process.exit(-1);
724
- }
725
- };
726
- this.stopPureSideCar = async (uid) => {
727
- console.log(ansiC.green(ansiC.inverse(`stopPureSideCar ${uid}`)));
728
- await this.sidecars[uid].shutdown();
729
- return;
730
- };
731
- this.launchPureSideCar = async (sidecar) => {
732
- console.log(ansiC.green(ansiC.inverse(`launchPureSideCar ${sidecar[0]}`)));
733
- const r = Math.random();
734
- const dest = process.cwd() + `/testeranto/bundles/pure/${this.name}/${sidecar[0]}`;
735
- const builtfile = dest.split(".").slice(0, -1).concat("mjs").join(".");
736
- const destFolder = dest.replace(".mjs", "");
737
- let argz;
738
- const z = sidecar[2];
739
- const testConfigResource = sidecar[2];
740
- const src = sidecar[0];
741
- const portsToUse = [];
742
- if (testConfigResource.ports === 0) {
743
- argz = {
744
- // scheduled: true,
745
- name: src,
746
- ports: portsToUse,
747
- fs: destFolder,
748
- browserWSEndpoint: this.browser.wsEndpoint(),
749
- };
750
- }
751
- else if (testConfigResource.ports > 0) {
752
- const openPorts = Object.entries(this.ports).filter(([portnumber, portopen]) => portopen === "");
753
- if (openPorts.length >= testConfigResource.ports) {
754
- for (let i = 0; i < testConfigResource.ports; i++) {
755
- portsToUse.push(Number(openPorts[i][0]));
756
- this.ports[openPorts[i][0]] = src; // port is now claimed
270
+ }).finally(() => {
271
+ for (let i = 0; i <= portsToUse.length; i++) {
272
+ if (portsToUse[i]) {
273
+ this.ports[portsToUse[i]] = ""; //port is open again
274
+ }
757
275
  }
758
- argz = {
759
- // scheduled: true,
760
- name: src,
761
- // ports: [3333],
762
- ports: portsToUse,
763
- fs: ".",
764
- browserWSEndpoint: this.browser.wsEndpoint(),
765
- };
766
- }
767
- else {
768
- this.queue.push(src);
769
- // return;
770
- }
771
- }
772
- else {
773
- console.error("negative port makes no sense", src);
774
- process.exit(-1);
775
- }
776
- // const builtfile = dest + ".mjs";
777
- await import(`${builtfile}?cacheBust=${Date.now()}`).then((module) => {
778
- if (!this.pureSidecars)
779
- this.pureSidecars = {};
780
- this.pureSidecars[r] = module.default;
781
- this.pureSidecars[r].start(argz);
782
- });
783
- return [r, argz];
784
- // for (let i = 0; i <= portsToUse.length; i++) {
785
- // if (portsToUse[i]) {
786
- // this.ports[portsToUse[i]] = "true"; //port is open again
787
- // }
788
- // }
789
- };
790
- this.launchPitono = async (src, dest) => {
791
- console.log(ansiC.green(ansiC.inverse(`pitono < ${src}`)));
792
- this.bddTestIsRunning(src);
793
- const reportDest = `testeranto/reports/${this.name}/${src
794
- .split(".")
795
- .slice(0, -1)
796
- .join(".")}/pitono`;
797
- if (!fs.existsSync(reportDest)) {
798
- fs.mkdirSync(reportDest, { recursive: true });
799
- }
800
- const logs = createLogStreams(reportDest, "node"); // Use node-style logs for pitono
801
- try {
802
- // Execute the Python test using the pitono runner
803
- const { PitonoRunner } = await import('./pitonoRunner');
804
- const runner = new PitonoRunner(this.configs, this.name);
805
- await runner.run();
806
- this.bddTestIsNowDone(src, 0);
807
- statusMessagePretty(0, src, "pitono");
808
- }
809
- catch (error) {
810
- logs.writeExitCode(-1, error);
811
- console.log(ansiC.red(ansiC.inverse(`${src} errored with: ${error}. Check logs for more info`)));
812
- this.bddTestIsNowDone(src, -1);
813
- statusMessagePretty(-1, src, "pitono");
814
- }
276
+ });
277
+ })();
278
+ // Add to process manager
279
+ this.addPromiseProcess(processId, nodePromise, command, "bdd-test", src, "node");
815
280
  };
816
281
  this.launchWeb = async (src, dest) => {
817
- console.log(ansiC.green(ansiC.inverse(`web < ${src}`)));
818
- this.bddTestIsRunning(src);
819
- const reportDest = `testeranto/reports/${this.name}/${src
820
- .split(".")
821
- .slice(0, -1)
822
- .join(".")}/web`;
823
- if (!fs.existsSync(reportDest)) {
824
- fs.mkdirSync(reportDest, { recursive: true });
825
- }
826
- const destFolder = dest.replace(".mjs", "");
827
- const webArgz = JSON.stringify({
828
- name: src,
829
- ports: [].toString(),
830
- fs: reportDest,
831
- browserWSEndpoint: this.browser.wsEndpoint(),
832
- });
833
- const d = `${dest}?cacheBust=${Date.now()}`;
834
- const logs = createLogStreams(reportDest, "web");
835
- this.browser
836
- .newPage()
837
- .then((page) => {
838
- page.on("console", (log) => {
839
- var _a, _b, _c, _d;
840
- const msg = `${log.text()}\n`;
841
- switch (log.type()) {
842
- case "info":
843
- (_a = logs.info) === null || _a === void 0 ? void 0 : _a.write(msg);
844
- break;
845
- case "warn":
846
- (_b = logs.warn) === null || _b === void 0 ? void 0 : _b.write(msg);
847
- break;
848
- case "error":
849
- (_c = logs.error) === null || _c === void 0 ? void 0 : _c.write(msg);
850
- break;
851
- case "debug":
852
- (_d = logs.debug) === null || _d === void 0 ? void 0 : _d.write(msg);
853
- break;
854
- default:
855
- break;
856
- }
857
- });
858
- page.on("close", () => {
859
- logs.writeExitCode(0); // Web tests exit with 0 unless there's an error
860
- logs.closeAll();
861
- logs.closeAll();
282
+ const processId = `web-${src}-${Date.now()}`;
283
+ const command = `web test: ${src}`;
284
+ // Create the promise
285
+ const webPromise = (async () => {
286
+ this.bddTestIsRunning(src);
287
+ const reportDest = `testeranto/reports/${this.name}/${src
288
+ .split(".")
289
+ .slice(0, -1)
290
+ .join(".")}/web`;
291
+ if (!fs.existsSync(reportDest)) {
292
+ fs.mkdirSync(reportDest, { recursive: true });
293
+ }
294
+ const destFolder = dest.replace(".mjs", "");
295
+ const webArgz = JSON.stringify({
296
+ name: src,
297
+ ports: [].toString(),
298
+ fs: reportDest,
299
+ browserWSEndpoint: this.browser.wsEndpoint(),
862
300
  });
863
- this.mapping().forEach(async ([command, func]) => {
864
- if (command === "page") {
865
- page.exposeFunction(command, (x) => {
866
- if (x) {
867
- return func(x);
301
+ const d = `${dest}?cacheBust=${Date.now()}`;
302
+ const logs = createLogStreams(reportDest, "web");
303
+ return new Promise((resolve, reject) => {
304
+ this.browser
305
+ .newPage()
306
+ .then((page) => {
307
+ page.on("console", (log) => {
308
+ var _a, _b, _c, _d;
309
+ const msg = `${log.text()}\n`;
310
+ switch (log.type()) {
311
+ case "info":
312
+ (_a = logs.info) === null || _a === void 0 ? void 0 : _a.write(msg);
313
+ break;
314
+ case "warn":
315
+ (_b = logs.warn) === null || _b === void 0 ? void 0 : _b.write(msg);
316
+ break;
317
+ case "error":
318
+ (_c = logs.error) === null || _c === void 0 ? void 0 : _c.write(msg);
319
+ break;
320
+ case "debug":
321
+ (_d = logs.debug) === null || _d === void 0 ? void 0 : _d.write(msg);
322
+ break;
323
+ default:
324
+ break;
325
+ }
326
+ });
327
+ page.on("close", () => {
328
+ logs.writeExitCode(0);
329
+ logs.closeAll();
330
+ });
331
+ this.mapping().forEach(async ([command, func]) => {
332
+ if (command === "page") {
333
+ page.exposeFunction(command, (x) => {
334
+ if (x) {
335
+ return func(x);
336
+ }
337
+ else {
338
+ return func(page.mainFrame()._id);
339
+ }
340
+ });
868
341
  }
869
342
  else {
870
- return func(page.mainFrame()._id);
343
+ return page.exposeFunction(command, func);
871
344
  }
872
345
  });
873
- }
874
- else {
875
- return page.exposeFunction(command, func);
876
- }
877
- });
878
- return page;
879
- })
880
- .then(async (page) => {
881
- const close = () => {
882
- if (!files[src]) {
883
- files[src] = new Set();
884
- }
885
- // files[t].add(filepath);
886
- // fs.writeFileSync(
887
- // destFolder + "/manifest.json",
888
- // JSON.stringify(Array.from(files[src]))
889
- // );
890
- delete files[src];
891
- Promise.all(screenshots[src] || []).then(() => {
892
- delete screenshots[src];
893
- page.close();
346
+ return page;
347
+ })
348
+ .then(async (page) => {
349
+ const close = () => {
350
+ if (!files[src]) {
351
+ files[src] = new Set();
352
+ }
353
+ delete files[src];
354
+ Promise.all(screenshots[src] || []).then(() => {
355
+ delete screenshots[src];
356
+ page.close();
357
+ });
358
+ };
359
+ page.on("pageerror", (err) => {
360
+ logs.writeExitCode(-1, err);
361
+ console.log(ansiColors.red(`web ! ${src} failed to execute No "tests.json" file was generated. Check ${reportDest}/error.log for more info`));
362
+ this.bddTestIsNowDone(src, -1);
363
+ close();
364
+ reject(err);
365
+ });
366
+ await page.goto(`file://${`${destFolder}.html`}`, {});
367
+ await page
368
+ .evaluate(webEvaluator(d, webArgz))
369
+ .then(async ({ fails, failed, features }) => {
370
+ statusMessagePretty(fails, src, "web");
371
+ this.bddTestIsNowDone(src, fails);
372
+ resolve();
373
+ })
374
+ .catch((e) => {
375
+ console.log(ansiC.red(ansiC.inverse(e.stack)));
376
+ console.log(ansiC.red(ansiC.inverse(`web ! ${src} failed to execute. No "tests.json" file was generated. Check logs for more info`)));
377
+ this.bddTestIsNowDone(src, -1);
378
+ reject(e);
379
+ })
380
+ .finally(() => {
381
+ close();
382
+ });
383
+ })
384
+ .catch((error) => {
385
+ reject(error);
894
386
  });
895
- return;
896
- };
897
- page.on("pageerror", (err) => {
898
- logs.writeExitCode(-1, err);
899
- console.log(ansiColors.red(`web ! ${src} failed to execute No "tests.json" file was generated. Check ${reportDest}/error.log for more info`));
900
- this.bddTestIsNowDone(src, -1);
901
- close();
902
- });
903
- // page.on("console", (log: ConsoleMessage) => {});
904
- await page.goto(`file://${`${destFolder}.html`}`, {});
905
- await page
906
- .evaluate(`
907
- import('${d}').then(async (x) => {
908
- try {
909
- return await (await x.default).receiveTestResourceConfig(${webArgz})
910
- } catch (e) {
911
- console.log("web run failure", e.toString())
912
- }
913
- })
914
- `)
915
- .then(async ({ fails, failed, features }) => {
916
- statusMessagePretty(fails, src, "web");
917
- this.bddTestIsNowDone(src, fails);
918
- // close();
919
- })
920
- .catch((e) => {
921
- console.log(ansiC.red(ansiC.inverse(e.stack)));
922
- console.log(ansiC.red(ansiC.inverse(`web ! ${src} failed to execute. No "tests.json" file was generated. Check logs for more info`)));
923
- this.bddTestIsNowDone(src, -1);
924
- })
925
- .finally(() => {
926
- // process.exit(-1);
927
- close();
928
387
  });
929
- return page;
930
- });
388
+ })();
389
+ // Add to process manager
390
+ this.addPromiseProcess(processId, webPromise, command, "bdd-test", src, "web");
931
391
  };
932
- this.receiveFeaturesV2 = (reportDest, srcTest, platform) => {
933
- const featureDestination = path.resolve(process.cwd(), "reports", "features", "strings", srcTest.split(".").slice(0, -1).join(".") + ".features.txt");
934
- // Read and parse the test report
935
- const testReportPath = `${reportDest}/tests.json`;
936
- if (!fs.existsSync(testReportPath)) {
937
- console.error(`tests.json not found at: ${testReportPath}`);
938
- return;
939
- }
940
- const testReport = JSON.parse(fs.readFileSync(testReportPath, "utf8"));
941
- // Add full path information to each test
942
- if (testReport.tests) {
943
- testReport.tests.forEach((test) => {
944
- // Add the full path to each test
945
- test.fullPath = path.resolve(process.cwd(), srcTest);
946
- });
947
- }
948
- // Add full path to the report itself
949
- testReport.fullPath = path.resolve(process.cwd(), srcTest);
950
- // Write the modified report back
951
- fs.writeFileSync(testReportPath, JSON.stringify(testReport, null, 2));
952
- testReport.features
953
- .reduce(async (mm, featureStringKey) => {
954
- const accum = await mm;
955
- const isUrl = isValidUrl(featureStringKey);
956
- if (isUrl) {
957
- const u = new URL(featureStringKey);
958
- if (u.protocol === "file:") {
959
- const newPath = `${process.cwd()}/testeranto/features/internal/${path.relative(process.cwd(), u.pathname)}`;
960
- // await fs.promises.mkdir(path.dirname(newPath), { recursive: true });
961
- // try {
962
- // await fs.unlinkSync(newPath);
963
- // // console.log(`Removed existing link at ${newPath}`);
964
- // } catch (error) {
965
- // if (error.code !== "ENOENT") {
966
- // // throw error;
967
- // }
968
- // }
969
- // fs.symlink(u.pathname, newPath, (err) => {
970
- // if (err) {
971
- // // console.error("Error creating symlink:", err);
972
- // } else {
973
- // // console.log("Symlink created successfully");
974
- // }
975
- // });
976
- accum.files.push(u.pathname);
977
- }
978
- else if (u.protocol === "http:" || u.protocol === "https:") {
979
- const newPath = `${process.cwd()}/testeranto/features/external/${u.hostname}${u.pathname}`;
980
- const body = await this.configs.featureIngestor(featureStringKey);
981
- writeFileAndCreateDir(newPath, body);
982
- accum.files.push(newPath);
983
- }
984
- }
985
- else {
986
- await fs.promises.mkdir(path.dirname(featureDestination), {
987
- recursive: true,
988
- });
989
- accum.strings.push(featureStringKey);
990
- }
991
- return accum;
992
- }, Promise.resolve({ files: [], strings: [] }))
993
- .then(({ files, strings }) => {
994
- // Markdown files must be referenced in the prompt but string style features are already present in the tests.json file
995
- fs.writeFileSync(`testeranto/reports/${this.name}/${srcTest
392
+ this.launchPython = async (src, dest) => {
393
+ const processId = `python-${src}-${Date.now()}`;
394
+ const command = `python test: ${src}`;
395
+ const pythonPromise = (async () => {
396
+ this.bddTestIsRunning(src);
397
+ const reportDest = `testeranto/reports/${this.name}/${src
996
398
  .split(".")
997
399
  .slice(0, -1)
998
- .join(".")}/${platform}/featurePrompt.txt`, files
999
- .map((f) => {
1000
- return `/read ${f}`;
1001
- })
1002
- .join("\n"));
1003
- });
1004
- // const f: Record<string, string> = {};
1005
- testReport.givens.forEach((g) => {
1006
- if (g.failed === true) {
1007
- this.summary[srcTest].failingFeatures[g.key] = g.features;
1008
- }
1009
- });
1010
- // this.summary[srcTest].failingFeatures = f;
1011
- this.writeBigBoard();
1012
- };
1013
- this.checkForShutdown = () => {
1014
- // console.log(ansiC.inverse(JSON.stringify(this.summary, null, 2)));
1015
- this.checkQueue();
1016
- console.log(ansiC.inverse(`The following jobs are awaiting resources: ${JSON.stringify(this.queue)}`));
1017
- console.log(ansiC.inverse(`The status of ports: ${JSON.stringify(this.ports)}`));
1018
- this.writeBigBoard();
1019
- if (this.mode === "dev")
1020
- return;
1021
- let inflight = false;
1022
- Object.keys(this.summary).forEach((k) => {
1023
- if (this.summary[k].prompt === "?") {
1024
- console.log(ansiC.blue(ansiC.inverse(`🕕 prompt ${k}`)));
1025
- inflight = true;
400
+ .join(".")}/python`;
401
+ if (!fs.existsSync(reportDest)) {
402
+ fs.mkdirSync(reportDest, { recursive: true });
1026
403
  }
1027
- });
1028
- Object.keys(this.summary).forEach((k) => {
1029
- if (this.summary[k].runTimeErrors === "?") {
1030
- console.log(ansiC.blue(ansiC.inverse(`🕕 runTimeError ${k}`)));
1031
- inflight = true;
404
+ let testResources = "";
405
+ const testConfig = this.configs.tests.find((t) => t[0] === src);
406
+ if (!testConfig) {
407
+ console.log(ansiColors.inverse(`missing test config! Exiting ungracefully for '${src}'`));
408
+ process.exit(-1);
1032
409
  }
1033
- });
1034
- Object.keys(this.summary).forEach((k) => {
1035
- if (this.summary[k].staticErrors === "?") {
1036
- console.log(ansiC.blue(ansiC.inverse(`🕕 staticErrors ${k}`)));
1037
- inflight = true;
1038
- }
1039
- });
1040
- Object.keys(this.summary).forEach((k) => {
1041
- if (this.summary[k].typeErrors === "?") {
1042
- console.log(ansiC.blue(ansiC.inverse(`🕕 typeErrors ${k}`)));
1043
- inflight = true;
1044
- }
1045
- });
1046
- this.writeBigBoard();
1047
- if (!inflight) {
1048
- if (this.browser) {
1049
- if (this.browser) {
1050
- this.browser.disconnect().then(() => {
1051
- console.log(ansiC.inverse(`${this.name} has been tested. Goodbye.`));
1052
- process.exit();
1053
- });
1054
- }
410
+ const testConfigResource = testConfig[2];
411
+ const portsToUse = [];
412
+ if (testConfigResource.ports === 0) {
413
+ testResources = JSON.stringify({
414
+ scheduled: true,
415
+ name: src,
416
+ ports: portsToUse,
417
+ fs: reportDest,
418
+ browserWSEndpoint: this.browser.wsEndpoint(),
419
+ });
1055
420
  }
1056
- }
1057
- };
1058
- this.launchers = {};
1059
- this.ports = {};
1060
- this.queue = [];
1061
- this.nodeSidecars = {};
1062
- this.webSidecars = {};
1063
- this.pureSidecars = {};
1064
- this.configs.ports.forEach((element) => {
1065
- this.ports[element] = ""; // set ports as open
1066
- });
1067
- // Create HTTP server
1068
- this.httpServer = http.createServer(this.requestHandler.bind(this));
1069
- // Start WebSocket server attached to the HTTP server
1070
- this.wss = new WebSocketServer({ server: this.httpServer });
1071
- this.wss.on("connection", (ws) => {
1072
- this.clients.add(ws);
1073
- console.log("Client connected");
1074
- ws.on("message", (data) => {
1075
- var _a, _b;
1076
- try {
1077
- const message = JSON.parse(data.toString());
1078
- if (message.type === "executeCommand") {
1079
- // Validate the command starts with 'aider'
1080
- if (message.command && message.command.trim().startsWith("aider")) {
1081
- console.log(`Executing command: ${message.command}`);
1082
- // Execute the command
1083
- const processId = Date.now().toString();
1084
- const child = spawn(message.command, {
1085
- shell: true,
1086
- cwd: process.cwd(),
1087
- });
1088
- // Track the process in both maps
1089
- this.runningProcesses.set(processId, child);
1090
- this.allProcesses.set(processId, {
1091
- child,
1092
- status: "running",
1093
- command: message.command,
1094
- pid: child.pid,
1095
- timestamp: new Date().toISOString(),
1096
- });
1097
- // Initialize logs for this process
1098
- this.processLogs.set(processId, []);
1099
- // Broadcast process started
1100
- this.broadcast({
1101
- type: "processStarted",
1102
- processId,
1103
- command: message.command,
1104
- timestamp: new Date().toISOString(),
1105
- logs: [],
1106
- });
1107
- // Capture stdout and stderr
1108
- (_a = child.stdout) === null || _a === void 0 ? void 0 : _a.on("data", (data) => {
1109
- const logData = data.toString();
1110
- // Add to stored logs
1111
- const logs = this.processLogs.get(processId) || [];
1112
- logs.push(logData);
1113
- this.processLogs.set(processId, logs);
1114
- this.broadcast({
1115
- type: "processStdout",
1116
- processId,
1117
- data: logData,
1118
- timestamp: new Date().toISOString(),
1119
- });
1120
- });
1121
- (_b = child.stderr) === null || _b === void 0 ? void 0 : _b.on("data", (data) => {
1122
- const logData = data.toString();
1123
- // Add to stored logs
1124
- const logs = this.processLogs.get(processId) || [];
1125
- logs.push(logData);
1126
- this.processLogs.set(processId, logs);
1127
- this.broadcast({
1128
- type: "processStderr",
1129
- processId,
1130
- data: logData,
1131
- timestamp: new Date().toISOString(),
1132
- });
1133
- });
1134
- child.on("error", (error) => {
1135
- console.error(`Failed to execute command: ${error}`);
1136
- this.runningProcesses.delete(processId);
1137
- // Update the process status to error
1138
- const processInfo = this.allProcesses.get(processId);
1139
- if (processInfo) {
1140
- this.allProcesses.set(processId, Object.assign(Object.assign({}, processInfo), { status: "error", error: error.message }));
1141
- }
1142
- this.broadcast({
1143
- type: "processError",
1144
- processId,
1145
- error: error.message,
1146
- timestamp: new Date().toISOString(),
1147
- });
1148
- });
1149
- child.on("exit", (code) => {
1150
- console.log(`Command exited with code ${code}`);
1151
- // Remove from running processes but keep in allProcesses
1152
- this.runningProcesses.delete(processId);
1153
- // Update the process status to exited
1154
- const processInfo = this.allProcesses.get(processId);
1155
- if (processInfo) {
1156
- this.allProcesses.set(processId, Object.assign(Object.assign({}, processInfo), { status: "exited", exitCode: code }));
1157
- }
1158
- this.broadcast({
1159
- type: "processExited",
1160
- processId,
1161
- exitCode: code,
1162
- timestamp: new Date().toISOString(),
1163
- });
1164
- });
421
+ else if (testConfigResource.ports > 0) {
422
+ const openPorts = Object.entries(this.ports).filter(([, status]) => status === "");
423
+ if (openPorts.length >= testConfigResource.ports) {
424
+ for (let i = 0; i < testConfigResource.ports; i++) {
425
+ portsToUse.push(openPorts[i][0]);
426
+ this.ports[openPorts[i][0]] = src;
1165
427
  }
1166
- else {
1167
- console.error('Invalid command: must start with "aider"');
1168
- }
1169
- }
1170
- else if (message.type === "getRunningProcesses") {
1171
- // Send list of all processes (both running and completed) with their full logs
1172
- const processes = Array.from(this.allProcesses.entries()).map(([id, procInfo]) => ({
1173
- processId: id,
1174
- command: procInfo.command,
1175
- pid: procInfo.pid,
1176
- status: procInfo.status,
1177
- exitCode: procInfo.exitCode,
1178
- error: procInfo.error,
1179
- timestamp: procInfo.timestamp,
1180
- logs: this.processLogs.get(id) || [],
1181
- }));
1182
- ws.send(JSON.stringify({
1183
- type: "runningProcesses",
1184
- processes,
1185
- }));
428
+ testResources = JSON.stringify({
429
+ scheduled: true,
430
+ name: src,
431
+ ports: portsToUse,
432
+ fs: reportDest,
433
+ browserWSEndpoint: this.browser.wsEndpoint(),
434
+ });
1186
435
  }
1187
- else if (message.type === "getProcess") {
1188
- // Send specific process with full logs
1189
- const processId = message.processId;
1190
- const procInfo = this.allProcesses.get(processId);
1191
- if (procInfo) {
1192
- ws.send(JSON.stringify({
1193
- type: "processData",
1194
- processId,
1195
- command: procInfo.command,
1196
- pid: procInfo.pid,
1197
- status: procInfo.status,
1198
- exitCode: procInfo.exitCode,
1199
- error: procInfo.error,
1200
- timestamp: procInfo.timestamp,
1201
- logs: this.processLogs.get(processId) || [],
1202
- }));
1203
- }
436
+ else {
437
+ console.log(ansiColors.red(`python: cannot run ${src} because there are no open ports ATM. This job will be enqueued and run again when a port is available`));
438
+ this.queue.push(src);
439
+ return;
1204
440
  }
1205
- else if (message.type === "stdin") {
1206
- // Handle stdin input for a process
1207
- const processId = message.processId;
1208
- const data = message.data;
1209
- console.log("Received stdin for process", processId, ":", data);
1210
- const childProcess = this.runningProcesses.get(processId);
1211
- if (childProcess && childProcess.stdin) {
1212
- console.log("Writing to process stdin");
1213
- childProcess.stdin.write(data);
441
+ }
442
+ else {
443
+ console.error("negative port makes no sense", src);
444
+ process.exit(-1);
445
+ }
446
+ const logs = createLogStreams(reportDest, "python");
447
+ // For Python, we'll just run the script directly and pass test resources as an argument
448
+ // Python tests need to handle their own IPC if needed
449
+ const child = spawn("python3", [src, testResources], {
450
+ stdio: ["pipe", "pipe", "pipe"],
451
+ });
452
+ return new Promise((resolve, reject) => {
453
+ var _a, _b;
454
+ (_a = child.stdout) === null || _a === void 0 ? void 0 : _a.on("data", (data) => {
455
+ var _a;
456
+ (_a = logs.stdout) === null || _a === void 0 ? void 0 : _a.write(data);
457
+ });
458
+ (_b = child.stderr) === null || _b === void 0 ? void 0 : _b.on("data", (data) => {
459
+ var _a;
460
+ (_a = logs.stderr) === null || _a === void 0 ? void 0 : _a.write(data);
461
+ });
462
+ child.on("close", (code) => {
463
+ const exitCode = code === null ? -1 : code;
464
+ if (exitCode < 0) {
465
+ logs.writeExitCode(exitCode, new Error("Process crashed or was terminated"));
1214
466
  }
1215
467
  else {
1216
- console.log("Cannot write to stdin - process not found or no stdin:", {
1217
- processExists: !!childProcess,
1218
- stdinExists: (childProcess === null || childProcess === void 0 ? void 0 : childProcess.stdin) ? true : false,
1219
- });
468
+ logs.writeExitCode(exitCode);
1220
469
  }
1221
- }
1222
- else if (message.type === "killProcess") {
1223
- // Handle killing a process
1224
- const processId = message.processId;
1225
- console.log("Received killProcess for process", processId);
1226
- const childProcess = this.runningProcesses.get(processId);
1227
- if (childProcess) {
1228
- console.log("Killing process");
1229
- childProcess.kill("SIGTERM");
1230
- // The process exit handler will update the status and broadcast the change
470
+ logs.closeAll();
471
+ if (exitCode === 0) {
472
+ this.bddTestIsNowDone(src, 0);
473
+ statusMessagePretty(0, src, "python");
474
+ resolve();
1231
475
  }
1232
476
  else {
1233
- console.log("Cannot kill process - process not found:", {
1234
- processExists: !!childProcess,
1235
- });
477
+ console.log(ansiColors.red(`python ! ${src} failed to execute. Check ${reportDest}/stderr.log for more info`));
478
+ this.bddTestIsNowDone(src, exitCode);
479
+ statusMessagePretty(exitCode, src, "python");
480
+ reject(new Error(`Process exited with code ${exitCode}`));
1236
481
  }
1237
- }
1238
- }
1239
- catch (error) {
1240
- console.error("Error handling WebSocket message:", error);
1241
- }
1242
- });
1243
- ws.on("close", () => {
1244
- this.clients.delete(ws);
1245
- console.log("Client disconnected");
1246
- });
1247
- ws.on("error", (error) => {
1248
- console.error("WebSocket error:", error);
1249
- this.clients.delete(ws);
1250
- });
1251
- });
1252
- // Start HTTP server
1253
- const httpPort = Number(process.env.HTTP_PORT) || 3000;
1254
- this.httpServer.listen(httpPort, () => {
1255
- console.log(`HTTP server running on http://localhost:${httpPort}`);
1256
- });
1257
- }
1258
- async stopSideCar(uid) {
1259
- console.log(ansiC.green(ansiC.inverse(`stopSideCar ${uid}`)));
1260
- Object.entries(this.pureSidecars).forEach(async ([k, v]) => {
1261
- if (Number(k) === uid) {
1262
- await this.pureSidecars[Number(k)].stop();
1263
- delete this.pureSidecars[Number(k)];
1264
- }
1265
- });
1266
- Object.entries(this.nodeSidecars).forEach(async ([k, v]) => {
1267
- if (Number(k) === uid) {
1268
- await this.nodeSidecars[Number(k)].send("stop");
1269
- delete this.nodeSidecars[Number(k)];
1270
- }
1271
- });
1272
- Object.entries(this.webSidecars).forEach(async ([k, v]) => {
1273
- if (Number(k) === uid) {
1274
- (await this.browser.pages()).forEach(async (p) => {
1275
- if (p.mainFrame()._id === k) {
1276
- await this.webSidecars[Number(k)].close();
1277
- delete this.webSidecars[Number(k)];
1278
- }
482
+ });
483
+ child.on("error", (e) => {
484
+ console.log(ansiColors.red(ansiColors.inverse(`python: ${src} errored with: ${e.name}. Check error logs for more info`)));
485
+ this.bddTestIsNowDone(src, -1);
486
+ statusMessagePretty(-1, src, "python");
487
+ reject(e);
488
+ });
489
+ }).finally(() => {
490
+ portsToUse.forEach(port => {
491
+ this.ports[port] = "";
492
+ });
1279
493
  });
1280
- }
1281
- });
1282
- return;
1283
- }
1284
- async launchSideCar(n, name) {
1285
- const c = this.configs.tests.find(([v, r]) => {
1286
- return v === name;
1287
- });
1288
- const s = c[3][n];
1289
- const r = s[1];
1290
- if (r === "node") {
1291
- return this.launchNodeSideCar(s);
1292
- }
1293
- else if (r === "web") {
1294
- return this.launchWebSideCar(s);
1295
- }
1296
- else if (r === "pure") {
1297
- return this.launchPureSideCar(s);
1298
- }
1299
- else {
1300
- throw `unknown runtime ${r}`;
1301
- }
1302
- }
1303
- mapping() {
1304
- return [
1305
- ["$", this.$],
1306
- ["click", this.click],
1307
- ["closePage", this.closePage],
1308
- ["createWriteStream", this.createWriteStream],
1309
- ["customclose", this.customclose],
1310
- ["customScreenShot", this.customScreenShot.bind(this)],
1311
- ["end", this.end],
1312
- ["existsSync", this.existsSync],
1313
- ["focusOn", this.focusOn],
1314
- ["getAttribute", this.getAttribute],
1315
- ["getInnerHtml", this.getInnerHtml],
1316
- // ["setValue", this.setValue],
1317
- ["goto", this.goto.bind(this)],
1318
- ["isDisabled", this.isDisabled],
1319
- ["launchSideCar", this.launchSideCar.bind(this)],
1320
- ["mkdirSync", this.mkdirSync],
1321
- ["newPage", this.newPage],
1322
- ["page", this.page],
1323
- ["pages", this.pages],
1324
- ["screencast", this.screencast],
1325
- ["screencastStop", this.screencastStop],
1326
- ["stopSideCar", this.stopSideCar.bind(this)],
1327
- ["typeInto", this.typeInto],
1328
- ["waitForSelector", this.waitForSelector],
1329
- ["write", this.write],
1330
- ["writeFileSync", this.writeFileSync],
1331
- ];
1332
- }
1333
- async start() {
1334
- // set up the "pure" listeners
1335
- this.mapping().forEach(async ([command, func]) => {
1336
- globalThis[command] = func;
1337
- });
1338
- if (!fs.existsSync(`testeranto/reports/${this.name}`)) {
1339
- fs.mkdirSync(`testeranto/reports/${this.name}`);
1340
- }
1341
- const executablePath = "/opt/homebrew/bin/chromium";
1342
- try {
1343
- this.browser = await puppeteer.launch({
1344
- slowMo: 1,
1345
- waitForInitialPage: false,
1346
- executablePath,
1347
- headless: true,
1348
- defaultViewport: null, // Disable default 800x600 viewport
1349
- dumpio: false,
1350
- devtools: false,
1351
- args: [
1352
- "--allow-file-access-from-files",
1353
- "--allow-insecure-localhost",
1354
- "--allow-running-insecure-content",
1355
- "--auto-open-devtools-for-tabs",
1356
- "--disable-dev-shm-usage",
1357
- "--disable-extensions",
1358
- "--disable-features=site-per-process",
1359
- "--disable-gpu",
1360
- "--disable-setuid-sandbox",
1361
- "--disable-site-isolation-trials",
1362
- "--disable-web-security",
1363
- "--no-first-run",
1364
- "--no-sandbox",
1365
- "--no-startup-window",
1366
- "--reduce-security-for-testing",
1367
- "--remote-allow-origins=*",
1368
- "--start-maximized",
1369
- "--unsafely-treat-insecure-origin-as-secure=*",
1370
- `--remote-debugging-port=3234`,
1371
- // "--disable-features=IsolateOrigins,site-per-process",
1372
- // "--disable-features=IsolateOrigins",
1373
- // "--disk-cache-dir=/dev/null",
1374
- // "--disk-cache-size=1",
1375
- // "--no-zygote",
1376
- // "--remote-allow-origins=ws://localhost:3234",
1377
- // "--single-process",
1378
- // "--start-maximized",
1379
- // "--unsafely-treat-insecure-origin-as-secure",
1380
- // "--unsafely-treat-insecure-origin-as-secure=ws://192.168.0.101:3234",
1381
- ],
1382
- });
1383
- }
1384
- catch (e) {
1385
- console.error(e);
1386
- console.error("could not start chrome via puppeter. Check this path: ", executablePath);
1387
- }
1388
- const { nodeEntryPoints, webEntryPoints, pureEntryPoints, pitonoEntryPoints } = this.getRunnables(this.configs.tests, this.name);
1389
- [
1390
- [
1391
- nodeEntryPoints,
1392
- this.launchNode,
1393
- "node",
1394
- (w) => {
1395
- this.nodeMetafileWatcher = w;
1396
- },
1397
- ],
1398
- [
1399
- webEntryPoints,
1400
- this.launchWeb,
1401
- "web",
1402
- (w) => {
1403
- this.webMetafileWatcher = w;
1404
- },
1405
- ],
1406
- [
1407
- pureEntryPoints,
1408
- this.launchPure,
1409
- "pure",
1410
- (w) => {
1411
- this.importMetafileWatcher = w;
1412
- },
1413
- ],
1414
- [
1415
- pitonoEntryPoints,
1416
- this.launchPitono,
1417
- "pitono",
1418
- (w) => {
1419
- this.pitonoMetafileWatcher = w;
1420
- },
1421
- ],
1422
- ].forEach(async ([eps, launcher, runtime, watcher]) => {
1423
- let metafile;
1424
- if (runtime === "pitono") {
1425
- metafile = `./testeranto/metafiles/python/core.json`;
1426
- // Ensure the directory exists before trying to watch
1427
- const metafileDir = path.dirname(metafile);
1428
- if (!fs.existsSync(metafileDir)) {
1429
- fs.mkdirSync(metafileDir, { recursive: true });
494
+ })();
495
+ this.addPromiseProcess(processId, pythonPromise, command, "bdd-test", src, "python");
496
+ };
497
+ this.launchGolang = async (src, dest) => {
498
+ const processId = `golang-${src}-${Date.now()}`;
499
+ const command = `golang test: ${src}`;
500
+ const golangPromise = (async () => {
501
+ this.bddTestIsRunning(src);
502
+ const reportDest = `testeranto/reports/${this.name}/${src
503
+ .split(".")
504
+ .slice(0, -1)
505
+ .join(".")}/golang`;
506
+ if (!fs.existsSync(reportDest)) {
507
+ fs.mkdirSync(reportDest, { recursive: true });
1430
508
  }
1431
- }
1432
- else {
1433
- metafile = `./testeranto/metafiles/${runtime}/${this.name}.json`;
1434
- }
1435
- // Only poll for file if it's not a pitono runtime
1436
- if (runtime !== "pitono") {
1437
- await pollForFile(metafile);
1438
- }
1439
- Object.entries(eps).forEach(async ([inputFile, outputFile]) => {
1440
- // await pollForFile(outputFile);\
1441
- this.launchers[inputFile] = () => launcher(inputFile, outputFile);
1442
- this.launchers[inputFile]();
1443
- try {
1444
- watch(outputFile, async (e, filename) => {
1445
- const hash = await fileHash(outputFile);
1446
- if (fileHashes[inputFile] !== hash) {
1447
- fileHashes[inputFile] = hash;
1448
- console.log(ansiC.yellow(ansiC.inverse(`< ${e} ${filename}`)));
1449
- // launcher(inputFile, outputFile);
1450
- this.launchers[inputFile]();
1451
- }
1452
- });
509
+ let testResources = "";
510
+ const testConfig = this.configs.tests.find((t) => t[0] === src);
511
+ if (!testConfig) {
512
+ console.log(ansiColors.inverse(`golang: missing test config! Exiting ungracefully for '${src}'`));
513
+ process.exit(-1);
1453
514
  }
1454
- catch (e) {
1455
- console.error(e);
515
+ const testConfigResource = testConfig[2];
516
+ const portsToUse = [];
517
+ if (testConfigResource.ports === 0) {
518
+ testResources = JSON.stringify({
519
+ scheduled: true,
520
+ name: src,
521
+ ports: portsToUse,
522
+ fs: reportDest,
523
+ browserWSEndpoint: this.browser.wsEndpoint(),
524
+ });
1456
525
  }
1457
- });
1458
- this.metafileOutputs(runtime);
1459
- // For pitono, we need to wait for the file to be created
1460
- if (runtime === "pitono") {
1461
- // Use polling to wait for the file to exist
1462
- const checkFileExists = () => {
1463
- if (fs.existsSync(metafile)) {
1464
- console.log(ansiC.green(ansiC.inverse(`Pitono metafile found: ${metafile}`)));
1465
- // Set up the watcher once the file exists
1466
- watcher(watch(metafile, async (e, filename) => {
1467
- console.log(ansiC.yellow(ansiC.inverse(`< ${e} ${filename} (${runtime})`)));
1468
- this.metafileOutputs(runtime);
1469
- }));
1470
- // Read the metafile immediately
1471
- this.metafileOutputs(runtime);
526
+ else if (testConfigResource.ports > 0) {
527
+ const openPorts = Object.entries(this.ports).filter(([, status]) => status === "");
528
+ if (openPorts.length >= testConfigResource.ports) {
529
+ for (let i = 0; i < testConfigResource.ports; i++) {
530
+ portsToUse.push(openPorts[i][0]);
531
+ this.ports[openPorts[i][0]] = src;
532
+ }
533
+ testResources = JSON.stringify({
534
+ scheduled: true,
535
+ name: src,
536
+ ports: portsToUse,
537
+ fs: reportDest,
538
+ browserWSEndpoint: this.browser.wsEndpoint(),
539
+ });
1472
540
  }
1473
541
  else {
1474
- // Check again after a delay
1475
- setTimeout(checkFileExists, 1000);
542
+ console.log(ansiColors.red(`golang: cannot run ${src} because there are no open ports ATM. This job will be enqueued and run again when a port is available`));
543
+ this.queue.push(src);
544
+ return;
1476
545
  }
1477
- };
1478
- // Start checking for the file
1479
- checkFileExists();
1480
- }
1481
- else {
1482
- // For other runtimes, only set up watcher if the file exists
1483
- if (fs.existsSync(metafile)) {
1484
- watcher(watch(metafile, async (e, filename) => {
1485
- console.log(ansiC.yellow(ansiC.inverse(`< ${e} ${filename} (${runtime})`)));
1486
- this.metafileOutputs(runtime);
1487
- }));
1488
- }
1489
- }
1490
- });
1491
- // Object.keys(this.configs.externalTests).forEach((et) => {
1492
- // this.launchExternalTest(et, this.configs.externalTests[et]);
1493
- // });
1494
- }
1495
- // async launchExternalTest(
1496
- // externalTestName: string,
1497
- // externalTest: {
1498
- // watch: string[];
1499
- // exec: string;
1500
- // }
1501
- // ) {
1502
- // // fs.mkdirSync(`testeranto/externalTests/${externalTestName}`);
1503
- // // exec(externalTest.exec, (error, stdout, stderr) => {
1504
- // // if (error) {
1505
- // // fs.writeFileSync(
1506
- // // `testeranto/externalTests/${externalTestName}/exitcode.txt`,
1507
- // // `${error.name}\n${error.message}\n${error.code}\n`
1508
- // // );
1509
- // // } else {
1510
- // // fs.writeFileSync(
1511
- // // `testeranto/externalTests/${externalTestName}/exitcode.txt`,
1512
- // // `0`
1513
- // // );
1514
- // // }
1515
- // // fs.writeFileSync(
1516
- // // `testeranto/externalTests/${externalTestName}/stdout.txt`,
1517
- // // stdout
1518
- // // );
1519
- // // fs.writeFileSync(
1520
- // // `testeranto/externalTests/${externalTestName}/stderr.txt`,
1521
- // // stderr
1522
- // // );
1523
- // // });
1524
- // }
1525
- async stop() {
1526
- console.log(ansiC.inverse("Testeranto-Run is shutting down gracefully..."));
1527
- this.mode = "once";
1528
- this.nodeMetafileWatcher.close();
1529
- this.webMetafileWatcher.close();
1530
- this.importMetafileWatcher.close();
1531
- if (this.pitonoMetafileWatcher) {
1532
- this.pitonoMetafileWatcher.close();
1533
- }
1534
- // Close any remaining log streams
1535
- Object.values(this.logStreams || {}).forEach((logs) => logs.closeAll());
1536
- // Close WebSocket server
1537
- this.wss.close(() => {
1538
- console.log("WebSocket server closed");
1539
- });
1540
- // Close all client connections
1541
- this.clients.forEach((client) => {
1542
- client.terminate();
1543
- });
1544
- this.clients.clear();
1545
- // Close HTTP server
1546
- this.httpServer.close(() => {
1547
- console.log("HTTP server closed");
1548
- });
1549
- this.checkForShutdown();
1550
- }
1551
- async metafileOutputs(platform) {
1552
- let metafilePath;
1553
- if (platform === "pitono") {
1554
- metafilePath = `./testeranto/metafiles/python/core.json`;
1555
- }
1556
- else {
1557
- metafilePath = `./testeranto/metafiles/${platform}/${this.name}.json`;
1558
- }
1559
- // Check if the file exists
1560
- if (!fs.existsSync(metafilePath)) {
1561
- if (platform === "pitono") {
1562
- console.log(ansiC.yellow(ansiC.inverse(`Pitono metafile not found yet: ${metafilePath}`)));
1563
- }
1564
- return;
1565
- }
1566
- let metafile;
1567
- try {
1568
- const fileContent = fs.readFileSync(metafilePath).toString();
1569
- const parsedData = JSON.parse(fileContent);
1570
- // Handle different metafile structures
1571
- if (platform === "pitono") {
1572
- // Pitono metafile might be the entire content or have a different structure
1573
- metafile = parsedData.metafile || parsedData;
1574
- }
1575
- else {
1576
- metafile = parsedData.metafile;
1577
- }
1578
- if (!metafile) {
1579
- console.log(ansiC.yellow(ansiC.inverse(`No metafile found in ${metafilePath}`)));
1580
- return;
1581
- }
1582
- }
1583
- catch (error) {
1584
- console.error(`Error reading metafile at ${metafilePath}:`, error);
1585
- return;
1586
- }
1587
- const outputs = metafile.outputs;
1588
- Object.keys(outputs).forEach(async (k) => {
1589
- const pattern = `testeranto/bundles/${platform}/${this.name}/${this.configs.src}`;
1590
- if (!k.startsWith(pattern)) {
1591
- return false;
1592
- }
1593
- const addableFiles = Object.keys(outputs[k].inputs).filter((i) => {
1594
- if (!fs.existsSync(i))
1595
- return false;
1596
- if (i.startsWith("node_modules"))
1597
- return false;
1598
- if (i.startsWith("./node_modules"))
1599
- return false;
1600
- return true;
1601
- });
1602
- const f = `${k.split(".").slice(0, -1).join(".")}/`;
1603
- if (!fs.existsSync(f)) {
1604
- fs.mkdirSync(f);
1605
- }
1606
- const entrypoint = outputs[k].entryPoint;
1607
- if (entrypoint) {
1608
- const changeDigest = await filesHash(addableFiles);
1609
- if (changeDigest === changes[entrypoint]) {
1610
- // skip
1611
546
  }
1612
547
  else {
1613
- changes[entrypoint] = changeDigest;
1614
- this.tscCheck({
1615
- platform,
1616
- addableFiles,
1617
- entrypoint: entrypoint,
1618
- });
1619
- this.eslintCheck(entrypoint, platform, addableFiles);
1620
- this.makePrompt(entrypoint, addableFiles, platform);
548
+ console.error("negative port makes no sense", src);
549
+ process.exit(-1);
1621
550
  }
1622
- }
1623
- });
1624
- }
1625
- requestHandler(req, res) {
1626
- // Parse the URL
1627
- const parsedUrl = url.parse(req.url || "/");
1628
- let pathname = parsedUrl.pathname || "/";
1629
- // Handle root path
1630
- if (pathname === "/") {
1631
- pathname = "/index.html";
1632
- }
1633
- // Remove leading slash
1634
- let filePath = pathname.substring(1);
1635
- // Determine which directory to serve from
1636
- if (filePath.startsWith("reports/")) {
1637
- // Serve from reports directory
1638
- filePath = `testeranto/${filePath}`;
1639
- }
1640
- else if (filePath.startsWith("metafiles/")) {
1641
- // Serve from metafiles directory
1642
- filePath = `testeranto/${filePath}`;
1643
- }
1644
- else if (filePath === "projects.json") {
1645
- // Serve projects.json
1646
- filePath = `testeranto/${filePath}`;
1647
- }
1648
- else {
1649
- // For frontend assets, try multiple possible locations
1650
- // First, try the dist directory
1651
- const possiblePaths = [
1652
- `dist/${filePath}`,
1653
- `testeranto/dist/${filePath}`,
1654
- `../dist/${filePath}`,
1655
- `./${filePath}`,
1656
- ];
1657
- // Find the first existing file
1658
- let foundPath = null;
1659
- for (const possiblePath of possiblePaths) {
1660
- if (fs.existsSync(possiblePath)) {
1661
- foundPath = possiblePath;
1662
- break;
1663
- }
1664
- }
1665
- if (foundPath) {
1666
- filePath = foundPath;
1667
- }
1668
- else {
1669
- // If no file found, serve index.html for SPA routing
1670
- const indexPath = this.findIndexHtml();
1671
- if (indexPath) {
1672
- fs.readFile(indexPath, (err, data) => {
1673
- if (err) {
1674
- res.writeHead(404, { "Content-Type": "text/plain" });
1675
- res.end("404 Not Found");
551
+ // Compile the Go test first
552
+ const buildDir = path.dirname(dest);
553
+ const binaryName = path.basename(dest, '.go');
554
+ const binaryPath = path.join(buildDir, binaryName);
555
+ const logs = createLogStreams(reportDest, "golang");
556
+ // First, compile the Go program
557
+ const compileProcess = spawn("go", ["build", "-o", binaryPath, dest]);
558
+ return new Promise((resolve, reject) => {
559
+ var _a, _b;
560
+ (_a = compileProcess.stdout) === null || _a === void 0 ? void 0 : _a.on("data", (data) => {
561
+ var _a;
562
+ (_a = logs.stdout) === null || _a === void 0 ? void 0 : _a.write(data);
563
+ });
564
+ (_b = compileProcess.stderr) === null || _b === void 0 ? void 0 : _b.on("data", (data) => {
565
+ var _a;
566
+ (_a = logs.stderr) === null || _a === void 0 ? void 0 : _a.write(data);
567
+ });
568
+ compileProcess.on("close", (compileCode) => {
569
+ var _a, _b;
570
+ if (compileCode !== 0) {
571
+ console.log(ansiColors.red(`golang ! ${src} failed to compile. Check ${reportDest}/stderr.log for more info`));
572
+ this.bddTestIsNowDone(src, compileCode || -1);
573
+ statusMessagePretty(compileCode || -1, src, "golang");
574
+ reject(new Error(`Compilation failed with code ${compileCode}`));
1676
575
  return;
1677
576
  }
1678
- res.writeHead(200, { "Content-Type": "text/html" });
1679
- res.end(data);
1680
- });
1681
- return;
1682
- }
1683
- else {
1684
- res.writeHead(404, { "Content-Type": "text/plain" });
1685
- res.end("404 Not Found");
1686
- return;
1687
- }
1688
- }
1689
- }
1690
- // Check if file exists
1691
- fs.exists(filePath, (exists) => {
1692
- if (!exists) {
1693
- // For SPA routing, serve index.html if the path looks like a route
1694
- if (!pathname.includes(".") && pathname !== "/") {
1695
- const indexPath = this.findIndexHtml();
1696
- if (indexPath) {
1697
- fs.readFile(indexPath, (err, data) => {
1698
- if (err) {
1699
- res.writeHead(404, { "Content-Type": "text/plain" });
1700
- res.end("404 Not Found");
1701
- return;
577
+ // Now run the compiled binary
578
+ const child = spawn(binaryPath, [testResources], {
579
+ stdio: ["pipe", "pipe", "pipe"],
580
+ });
581
+ (_a = child.stdout) === null || _a === void 0 ? void 0 : _a.on("data", (data) => {
582
+ var _a;
583
+ (_a = logs.stdout) === null || _a === void 0 ? void 0 : _a.write(data);
584
+ });
585
+ (_b = child.stderr) === null || _b === void 0 ? void 0 : _b.on("data", (data) => {
586
+ var _a;
587
+ (_a = logs.stderr) === null || _a === void 0 ? void 0 : _a.write(data);
588
+ });
589
+ child.on("close", (code) => {
590
+ const exitCode = code === null ? -1 : code;
591
+ if (exitCode < 0) {
592
+ logs.writeExitCode(exitCode, new Error("Process crashed or was terminated"));
593
+ }
594
+ else {
595
+ logs.writeExitCode(exitCode);
596
+ }
597
+ logs.closeAll();
598
+ if (exitCode === 0) {
599
+ this.bddTestIsNowDone(src, 0);
600
+ statusMessagePretty(0, src, "golang");
601
+ resolve();
602
+ }
603
+ else {
604
+ console.log(ansiColors.red(`golang ! ${src} failed to execute. Check ${reportDest}/stderr.log for more info`));
605
+ this.bddTestIsNowDone(src, exitCode);
606
+ statusMessagePretty(exitCode, src, "golang");
607
+ reject(new Error(`Process exited with code ${exitCode}`));
1702
608
  }
1703
- res.writeHead(200, { "Content-Type": "text/html" });
1704
- res.end(data);
1705
609
  });
1706
- return;
1707
- }
1708
- else {
1709
- // Serve a simple message if index.html is not found
1710
- res.writeHead(200, { "Content-Type": "text/html" });
1711
- res.end(`
1712
- <html>
1713
- <body>
1714
- <h1>Testeranto is running</h1>
1715
- <p>Frontend files are not built yet. Run 'npm run build' to build the frontend.</p>
1716
- </body>
1717
- </html>
1718
- `);
1719
- return;
1720
- }
1721
- }
1722
- res.writeHead(404, { "Content-Type": "text/plain" });
1723
- res.end("404 Not Found");
1724
- return;
1725
- }
1726
- // Read and serve the file
1727
- fs.readFile(filePath, (err, data) => {
1728
- if (err) {
1729
- res.writeHead(500, { "Content-Type": "text/plain" });
1730
- res.end("500 Internal Server Error");
1731
- return;
1732
- }
1733
- // Get MIME type
1734
- const mimeType = mime.lookup(filePath) || "application/octet-stream";
1735
- res.writeHead(200, { "Content-Type": mimeType });
1736
- res.end(data);
1737
- });
1738
- });
1739
- }
1740
- findIndexHtml() {
1741
- const possiblePaths = [
1742
- "dist/index.html",
1743
- "testeranto/dist/index.html",
1744
- "../dist/index.html",
1745
- "./index.html",
1746
- ];
1747
- for (const path of possiblePaths) {
1748
- if (fs.existsSync(path)) {
1749
- return path;
1750
- }
1751
- }
1752
- return null;
1753
- }
1754
- broadcast(message) {
1755
- const data = typeof message === "string" ? message : JSON.stringify(message);
1756
- this.clients.forEach((client) => {
1757
- if (client.readyState === 1) {
1758
- // WebSocket.OPEN
1759
- client.send(data);
1760
- }
1761
- });
1762
- }
1763
- checkQueue() {
1764
- const x = this.queue.pop();
1765
- if (!x) {
1766
- ansiC.inverse(`The following queue is empty`);
1767
- return;
1768
- }
1769
- const test = this.configs.tests.find((t) => t[0] === x);
1770
- if (!test)
1771
- throw `test is undefined ${x}`;
1772
- // const [src, runtime, ...xx]: [string, IRunTime, ...any] = test;
1773
- this.launchers[test[0]]();
610
+ child.on("error", (e) => {
611
+ console.log(ansiColors.red(ansiColors.inverse(`golang: ${src} errored with: ${e.name}. Check error logs for more info`)));
612
+ this.bddTestIsNowDone(src, -1);
613
+ statusMessagePretty(-1, src, "golang");
614
+ reject(e);
615
+ });
616
+ });
617
+ compileProcess.on("error", (e) => {
618
+ console.log(ansiColors.red(ansiColors.inverse(`golang: ${src} compilation errored with: ${e.name}. Check error logs for more info`)));
619
+ this.bddTestIsNowDone(src, -1);
620
+ statusMessagePretty(-1, src, "golang");
621
+ reject(e);
622
+ });
623
+ }).finally(() => {
624
+ portsToUse.forEach(port => {
625
+ this.ports[port] = "";
626
+ });
627
+ });
628
+ })();
629
+ this.addPromiseProcess(processId, golangPromise, command, "bdd-test", src, "golang");
630
+ };
1774
631
  }
1775
632
  }