testeranto 0.200.0 → 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 (376) hide show
  1. package/README.md +26 -1
  2. package/bundle.js +3 -2
  3. package/design-editor/DesignEditor.tsx +40 -241
  4. package/dist/common/design-editor/DesignEditor.js +33 -198
  5. package/dist/common/src/App.js +158 -16
  6. package/dist/common/src/PM/PM_WithBuild.js +135 -0
  7. package/dist/common/src/PM/PM_WithEslintAndTsc.js +79 -67
  8. package/dist/common/src/PM/PM_WithGit.js +517 -0
  9. package/dist/common/src/PM/PM_WithProcesses.js +519 -0
  10. package/dist/common/src/PM/PM_WithWebSocket.js +535 -0
  11. package/dist/common/src/PM/base.js +62 -0
  12. package/dist/common/src/PM/main.js +533 -1676
  13. package/dist/common/src/PM/metafileOutputs.js +78 -0
  14. package/dist/common/src/PM/node.js +0 -6
  15. package/dist/common/src/PM/pure.js +0 -8
  16. package/dist/common/src/PM/types.js +1 -0
  17. package/dist/common/src/PM/utils.js +210 -0
  18. package/dist/common/src/PM/web.js +0 -6
  19. package/dist/common/src/ReportServer.js +0 -10
  20. package/dist/common/src/ReportServerLib.js +0 -140
  21. package/dist/common/src/components/pure/AppFrame.js +68 -56
  22. package/dist/common/src/components/pure/ArtifactTree.js +80 -0
  23. package/dist/common/src/components/pure/BuildLogViewer.js +106 -0
  24. package/dist/common/src/components/pure/DebugEnv.js +30 -0
  25. package/dist/common/src/components/pure/FileTree.js +34 -0
  26. package/dist/common/src/components/pure/FileTreeItem.js +29 -0
  27. package/dist/common/src/components/pure/GitHubLoginButton.js +18 -0
  28. package/dist/common/src/components/pure/GitIntegrationView.js +342 -0
  29. package/dist/common/src/components/pure/ProcessManager.js +1 -0
  30. package/dist/common/src/components/pure/ProcessManagerView.js +73 -74
  31. package/dist/common/src/components/pure/ProjectPageView.js +4 -117
  32. package/dist/common/src/components/pure/Settings.js +121 -0
  33. package/dist/common/src/components/pure/Settings.test.js +34 -0
  34. package/dist/common/src/components/pure/SignIn.js +22 -0
  35. package/dist/common/src/components/pure/SingleProcessView.js +166 -213
  36. package/dist/common/src/components/pure/TestPageView.js +113 -368
  37. package/dist/common/src/components/pure/TestPageView_utils.js +117 -0
  38. package/dist/common/src/components/pure/TestTable.js +33 -0
  39. package/dist/common/src/components/pure/ToastNotification.js +14 -0
  40. package/dist/common/src/components/pure/UserProfile.js +27 -0
  41. package/dist/common/src/components/stateful/AuthCallbackPage.js +51 -0
  42. package/dist/common/src/components/stateful/FeaturesReporter.js +2 -1
  43. package/dist/common/src/components/stateful/FileTree.js +58 -39
  44. package/dist/common/src/components/stateful/GitIntegrationPage.js +12 -0
  45. package/dist/common/src/components/stateful/ProcessManagerPage.js +13 -15
  46. package/dist/common/src/components/stateful/ProjectPage.js +6 -5
  47. package/dist/common/src/components/stateful/ProjectsPage.js +17 -19
  48. package/dist/common/src/components/stateful/SingleProcessPage.js +16 -26
  49. package/dist/common/src/components/stateful/TestPage.js +7 -5
  50. package/dist/common/src/hooks/useGitMode.js +21 -0
  51. package/dist/common/src/lib/BaseSuite.test/mock.js +15 -8
  52. package/dist/common/src/lib/BaseSuite.test/test.js +56 -80
  53. package/dist/common/src/lib/Tiposkripto.js +24 -0
  54. package/dist/common/src/lib/Tiposkripto.test/MockTiposkripto.js +154 -10
  55. package/dist/common/src/lib/Tiposkripto.test/Tiposkripto.adapter.js +6 -12
  56. package/dist/common/src/lib/Tiposkripto.test/Tiposkripto.implementation.js +63 -23
  57. package/dist/common/src/lib/Tiposkripto.test/Tiposkripto.specification.js +14 -6
  58. package/dist/common/src/lib/pmProxy.test/specification.js +167 -52
  59. package/dist/common/src/services/FileService.js +505 -0
  60. package/dist/common/src/services/GitHubAuthService.js +184 -0
  61. package/dist/common/src/testeranto.js +38 -97
  62. package/dist/common/src/utils/api.js +12 -8
  63. package/dist/common/src/utils/gitTest.js +27 -0
  64. package/dist/common/src/utils.js +23 -13
  65. package/dist/common/testeranto.config.js +21 -17
  66. package/dist/common/tsconfig.common.tsbuildinfo +1 -1
  67. package/dist/module/design-editor/DesignEditor.js +33 -199
  68. package/dist/module/src/App.js +121 -15
  69. package/dist/module/src/PM/PM_WithBuild.js +128 -0
  70. package/dist/module/src/PM/PM_WithEslintAndTsc.js +79 -67
  71. package/dist/module/src/PM/PM_WithGit.js +477 -0
  72. package/dist/module/src/PM/PM_WithProcesses.js +479 -0
  73. package/dist/module/src/PM/PM_WithWebSocket.js +528 -0
  74. package/dist/module/src/PM/base.js +62 -0
  75. package/dist/module/src/PM/main.js +533 -1676
  76. package/dist/module/src/PM/metafileOutputs.js +78 -0
  77. package/dist/module/src/PM/node.js +0 -6
  78. package/dist/module/src/PM/pure.js +0 -8
  79. package/dist/module/src/PM/types.js +1 -1
  80. package/dist/module/src/PM/utils.js +196 -0
  81. package/dist/module/src/PM/web.js +0 -6
  82. package/dist/module/src/ReportServer.js +1 -9
  83. package/dist/module/src/ReportServerLib.js +1 -134
  84. package/dist/module/src/components/pure/AppFrame.js +66 -24
  85. package/dist/module/src/components/pure/ArtifactTree.js +80 -0
  86. package/dist/module/src/components/pure/BuildLogViewer.js +99 -0
  87. package/dist/module/src/components/pure/DebugEnv.js +23 -0
  88. package/dist/module/src/components/pure/FileTree.js +27 -0
  89. package/dist/module/src/components/pure/FileTreeItem.js +22 -0
  90. package/dist/module/src/components/pure/GitHubLoginButton.js +11 -0
  91. package/dist/module/src/components/pure/GitIntegrationView.js +305 -0
  92. package/dist/module/src/components/pure/ProcessManager.js +1 -0
  93. package/dist/module/src/components/pure/ProcessManagerView.js +74 -75
  94. package/dist/module/src/components/pure/ProjectPageView.js +5 -118
  95. package/dist/module/src/components/pure/Settings.js +84 -0
  96. package/dist/module/src/components/pure/Settings.test.js +29 -0
  97. package/dist/module/src/components/pure/SignIn.js +15 -0
  98. package/dist/module/src/components/pure/SingleProcessView.js +130 -214
  99. package/dist/module/src/components/pure/TestPageView.js +97 -352
  100. package/dist/module/src/components/pure/TestPageView_utils.js +109 -0
  101. package/dist/module/src/components/pure/TestTable.js +26 -0
  102. package/dist/module/src/components/pure/ToastNotification.js +7 -0
  103. package/dist/module/src/components/pure/UserProfile.js +20 -0
  104. package/dist/module/src/components/stateful/AuthCallbackPage.js +14 -0
  105. package/dist/module/src/components/stateful/FeaturesReporter.js +2 -1
  106. package/dist/module/src/components/stateful/FileTree.js +59 -33
  107. package/dist/module/src/components/stateful/GitIntegrationPage.js +5 -0
  108. package/dist/module/src/components/stateful/ProcessManagerPage.js +13 -15
  109. package/dist/module/src/components/stateful/ProjectPage.js +6 -5
  110. package/dist/module/src/components/stateful/ProjectsPage.js +16 -18
  111. package/dist/module/src/components/stateful/SingleProcessPage.js +16 -26
  112. package/dist/module/src/components/stateful/TestPage.js +8 -6
  113. package/dist/module/src/hooks/useGitMode.js +17 -0
  114. package/dist/module/src/lib/BaseSuite.test/mock.js +15 -8
  115. package/dist/module/src/lib/BaseSuite.test/test.js +56 -80
  116. package/dist/module/src/lib/Tiposkripto.js +24 -0
  117. package/dist/module/src/lib/Tiposkripto.test/MockTiposkripto.js +154 -10
  118. package/dist/module/src/lib/Tiposkripto.test/Tiposkripto.adapter.js +6 -12
  119. package/dist/module/src/lib/Tiposkripto.test/Tiposkripto.implementation.js +63 -23
  120. package/dist/module/src/lib/Tiposkripto.test/Tiposkripto.specification.js +14 -6
  121. package/dist/module/src/lib/pmProxy.test/specification.js +167 -52
  122. package/dist/module/src/services/FileService.js +468 -0
  123. package/dist/module/src/services/GitHubAuthService.js +180 -0
  124. package/dist/module/src/testeranto.js +38 -97
  125. package/dist/module/src/utils/api.js +10 -7
  126. package/dist/module/src/utils/gitTest.js +23 -0
  127. package/dist/module/src/utils.js +21 -12
  128. package/dist/module/testeranto.config.js +21 -17
  129. package/dist/module/tsconfig.module.tsbuildinfo +1 -1
  130. package/dist/prebuild/App.css +94 -121
  131. package/dist/prebuild/App.js +44601 -11225
  132. package/dist/prebuild/testeranto.mjs +4106 -0
  133. package/dist/types/design-editor/DesignEditor.d.ts +1 -18
  134. package/dist/types/src/App.d.ts +18 -0
  135. package/dist/types/src/PM/PM_WithBuild.d.ts +13 -0
  136. package/dist/types/src/PM/PM_WithEslintAndTsc.d.ts +2 -4
  137. package/dist/types/src/PM/PM_WithGit.d.ts +27 -0
  138. package/dist/types/src/PM/PM_WithProcesses.d.ts +29 -0
  139. package/dist/types/src/PM/PM_WithWebSocket.d.ts +108 -0
  140. package/dist/types/src/PM/base.d.ts +1 -1
  141. package/dist/types/src/PM/index.d.ts +0 -2
  142. package/dist/types/src/PM/main.d.ts +6 -77
  143. package/dist/types/src/PM/metafileOutputs.d.ts +0 -0
  144. package/dist/types/src/PM/node.d.ts +0 -2
  145. package/dist/types/src/PM/pure.d.ts +0 -2
  146. package/dist/types/src/PM/types.d.ts +118 -0
  147. package/dist/types/src/PM/utils.d.ts +35 -0
  148. package/dist/types/src/PM/web.d.ts +0 -2
  149. package/dist/types/src/Pure.d.ts +6 -1
  150. package/dist/types/src/ReportServer.d.ts +0 -1
  151. package/dist/types/src/ReportServerLib.d.ts +0 -1
  152. package/dist/types/src/Types.d.ts +1 -0
  153. package/dist/types/src/components/pure/ArtifactTree.d.ts +0 -0
  154. package/dist/types/src/components/pure/BuildLogViewer.d.ts +7 -0
  155. package/dist/types/src/components/pure/DebugEnv.d.ts +2 -0
  156. package/dist/types/src/components/pure/FileTree.d.ts +6 -0
  157. package/dist/types/src/components/pure/FileTreeItem.d.ts +8 -0
  158. package/dist/types/src/components/pure/GitHubLoginButton.d.ts +8 -0
  159. package/dist/types/src/components/pure/GitIntegrationView.d.ts +1 -0
  160. package/dist/types/src/components/pure/Settings.d.ts +1 -0
  161. package/dist/types/src/components/pure/Settings.test.d.ts +1 -0
  162. package/dist/types/src/components/pure/SignIn.d.ts +1 -0
  163. package/dist/types/src/components/pure/SingleProcessView.d.ts +10 -0
  164. package/dist/types/src/components/pure/TestPageView.d.ts +2 -1
  165. package/dist/types/src/components/pure/TestPageView_utils.d.ts +23 -0
  166. package/dist/types/src/components/pure/TestTable.d.ts +16 -0
  167. package/dist/types/src/components/pure/ToastNotification.d.ts +6 -0
  168. package/dist/types/src/components/pure/UserProfile.d.ts +2 -0
  169. package/dist/types/src/components/stateful/AuthCallbackPage.d.ts +2 -0
  170. package/dist/types/src/components/stateful/FileTree.d.ts +0 -8
  171. package/dist/types/src/components/stateful/GitIntegrationPage.d.ts +1 -0
  172. package/dist/types/src/hooks/useGitMode.d.ts +7 -0
  173. package/dist/types/src/lib/BaseSuite.test/mock.d.ts +2 -2
  174. package/dist/types/src/lib/BaseSuite.test/test.d.ts +4 -3
  175. package/dist/types/src/lib/Tiposkripto.d.ts +2 -0
  176. package/dist/types/src/lib/Tiposkripto.test/MockTiposkripto.d.ts +3 -0
  177. package/dist/types/src/lib/Tiposkripto.test/Tiposkripto.types.d.ts +5 -0
  178. package/dist/types/src/lib/index.d.ts +6 -0
  179. package/dist/types/src/services/FileService.d.ts +34 -0
  180. package/dist/types/src/services/GitHubAuthService.d.ts +32 -0
  181. package/dist/types/src/utils/api.d.ts +1 -0
  182. package/dist/types/src/utils/gitTest.d.ts +11 -0
  183. package/dist/types/src/utils.d.ts +3 -3
  184. package/dist/types/tsconfig.types.tsbuildinfo +1 -1
  185. package/example/__pycache__/Calculator.cpython-313.pyc +0 -0
  186. package/example/vendor/github.com/adamwong246/testeranto/src/golingvu/README.md +187 -0
  187. package/example/vendor/github.com/adamwong246/testeranto/src/golingvu/base_given.go +163 -0
  188. package/example/vendor/github.com/adamwong246/testeranto/src/golingvu/base_suite.go +85 -0
  189. package/example/vendor/github.com/adamwong246/testeranto/src/golingvu/base_then.go +21 -0
  190. package/example/vendor/github.com/adamwong246/testeranto/src/golingvu/base_when.go +21 -0
  191. package/example/vendor/github.com/adamwong246/testeranto/src/golingvu/golingvu.go +554 -0
  192. package/example/vendor/github.com/adamwong246/testeranto/src/golingvu/test_adapter.go +33 -0
  193. package/example/vendor/github.com/adamwong246/testeranto/src/golingvu/types.go +72 -0
  194. package/example/vendor/modules.txt +5 -0
  195. package/git-integration-plan.md +395 -0
  196. package/package.json +26 -14
  197. package/src/App.tsx +169 -18
  198. package/src/PM/PM_WithBuild.ts +171 -0
  199. package/src/PM/PM_WithEslintAndTsc.ts +109 -86
  200. package/src/PM/PM_WithGit.ts +585 -0
  201. package/src/PM/PM_WithProcesses.ts +639 -0
  202. package/src/PM/PM_WithWebSocket.ts +631 -0
  203. package/src/PM/base.ts +63 -1
  204. package/src/PM/index.ts +8 -5
  205. package/src/PM/main.ts +672 -2050
  206. package/src/PM/metafileOutputs.ts +90 -0
  207. package/src/PM/node.ts +18 -18
  208. package/src/PM/pure.ts +5 -13
  209. package/src/PM/types.ts +145 -0
  210. package/src/PM/utils.ts +256 -0
  211. package/src/PM/web.ts +8 -8
  212. package/src/README.md +122 -0
  213. package/src/ReportServer.ts +0 -12
  214. package/src/ReportServerLib.ts +0 -147
  215. package/src/Types.ts +1 -0
  216. package/src/app.scss +14 -164
  217. package/src/components/pure/AppFrame.tsx +237 -71
  218. package/src/components/pure/ArtifactTree.tsx +82 -0
  219. package/src/components/pure/BuildLogViewer.tsx +168 -0
  220. package/src/components/pure/DebugEnv.tsx +30 -0
  221. package/src/components/pure/FileTree.tsx +58 -0
  222. package/src/components/pure/FileTreeItem.tsx +49 -0
  223. package/src/components/pure/GitHubLoginButton.tsx +31 -0
  224. package/src/components/pure/GitIntegrationView.tsx +443 -0
  225. package/src/components/pure/ProcessManager.tsx +6 -5
  226. package/src/components/pure/ProcessManagerView.tsx +162 -166
  227. package/src/components/pure/ProjectPageView.tsx +6 -224
  228. package/src/components/pure/Settings.test.tsx +34 -0
  229. package/src/components/pure/Settings.tsx +163 -0
  230. package/src/components/pure/SignIn.tsx +33 -0
  231. package/src/components/pure/SingleProcessView.tsx +231 -235
  232. package/src/components/pure/TestPageView.test/specification.ts +1 -0
  233. package/src/components/pure/TestPageView.tsx +317 -826
  234. package/src/components/pure/TestPageView_utils.tsx +285 -0
  235. package/src/components/pure/TestTable.tsx +88 -0
  236. package/src/components/pure/ToastNotification.tsx +19 -0
  237. package/src/components/pure/UserProfile.tsx +44 -0
  238. package/src/components/stateful/AuthCallbackPage.tsx +21 -0
  239. package/src/components/stateful/FeaturesReporter.tsx +3 -1
  240. package/src/components/stateful/FileTree.tsx +58 -58
  241. package/src/components/stateful/GitIntegrationPage.tsx +8 -0
  242. package/src/components/stateful/ProcessManagerPage.tsx +13 -17
  243. package/src/components/stateful/ProjectPage.tsx +6 -5
  244. package/src/components/stateful/ProjectsPage.tsx +17 -19
  245. package/src/components/stateful/SVGEditor/CircleForm.tsx +68 -0
  246. package/src/components/stateful/SVGEditor/GroupForm.tsx +56 -0
  247. package/src/components/stateful/SVGEditor/RectForm.tsx +74 -0
  248. package/src/components/stateful/SVGEditor/SVGAttributeField.tsx +29 -0
  249. package/src/components/stateful/SVGEditor/SVGAttributesEditor.tsx +73 -0
  250. package/src/components/stateful/SVGEditor/SVGEditorControls.tsx +45 -0
  251. package/src/components/stateful/SVGEditor/SVGElementForm.tsx +45 -0
  252. package/src/components/stateful/SVGEditor/SVGPreview.tsx +225 -0
  253. package/src/components/stateful/SVGEditor/SVGTextEditor.tsx +166 -0
  254. package/src/components/stateful/SVGEditor/SVGTree.tsx +159 -0
  255. package/src/components/stateful/SVGEditor/SVGTypes.ts +36 -0
  256. package/src/components/stateful/SVGEditor/svg.xsd.xml +3038 -0
  257. package/src/components/stateful/SVGEditorPage.tsx +503 -0
  258. package/src/components/stateful/SingleProcessPage.tsx +18 -31
  259. package/src/components/stateful/TestPage.tsx +25 -22
  260. package/src/golingvu/golingvu.go +38 -2
  261. package/src/hooks/useGitMode.ts +20 -0
  262. package/src/lib/BaseSuite.test/mock.ts +16 -10
  263. package/src/lib/BaseSuite.test/test.ts +144 -103
  264. package/src/lib/Tiposkripto.test/MockTiposkripto.ts +178 -14
  265. package/src/lib/Tiposkripto.test/Tiposkripto.adapter.ts +9 -14
  266. package/src/lib/Tiposkripto.test/Tiposkripto.implementation.ts +78 -38
  267. package/src/lib/Tiposkripto.test/Tiposkripto.specification.ts +51 -9
  268. package/src/lib/Tiposkripto.test/Tiposkripto.types.ts +5 -0
  269. package/src/lib/Tiposkripto.ts +27 -0
  270. package/src/lib/index.ts +7 -0
  271. package/src/lib/pmProxy.test/specification.ts +168 -166
  272. package/src/pitono/PM/__pycache__/python.cpython-313.pyc +0 -0
  273. package/src/pitono/__pycache__/Pitono.cpython-313.pyc +0 -0
  274. package/src/pitono/__pycache__/__init__.cpython-313.pyc +0 -0
  275. package/src/pitono/__pycache__/base_given.cpython-313.pyc +0 -0
  276. package/src/pitono/__pycache__/base_suite.cpython-313.pyc +0 -0
  277. package/src/pitono/__pycache__/base_then.cpython-313.pyc +0 -0
  278. package/src/pitono/__pycache__/base_when.cpython-313.pyc +0 -0
  279. package/src/pitono/__pycache__/core_generator.cpython-313.pyc +0 -0
  280. package/src/pitono/__pycache__/simple_adapter.cpython-313.pyc +0 -0
  281. package/src/pitono/__pycache__/types.cpython-313.pyc +0 -0
  282. package/src/services/FileService.ts +542 -0
  283. package/src/services/GitHubAuthService.ts +240 -0
  284. package/src/testeranto.ts +62 -140
  285. package/src/utils/api.ts +15 -13
  286. package/src/utils/gitTest.ts +29 -0
  287. package/src/utils.ts +21 -12
  288. package/testeranto/App.css +94 -121
  289. package/testeranto/App.js +44601 -11225
  290. package/testeranto/bundles/golang/core/Calculator.golingvu.go +53 -0
  291. package/testeranto/bundles/golang/core/Calculator.golingvu.golingvu.go +53 -0
  292. package/testeranto/bundles/node/core/chunk-RIM6RECA.mjs +1170 -0
  293. package/testeranto/bundles/node/core/chunk-VXVF7WFO.mjs +4321 -0
  294. package/testeranto/bundles/node/core/example/Calculator.test.mjs +503 -0
  295. package/testeranto/bundles/node/core/src/lib/BaseSuite.test/node.test.mjs +94 -1231
  296. package/testeranto/bundles/node/core/src/lib/TipoSkripto.test/TipoSkripto.mjs +574 -0
  297. package/testeranto/bundles/node/core/src/lib/pmProxy.test/index.mjs +482 -0
  298. package/testeranto/bundles/pure/core/chunk-XYOCRDEQ.mjs +1080 -0
  299. package/testeranto/bundles/pure/core/src/Pure.test.mjs +410 -0
  300. package/testeranto/bundles/pure/core/src/lib/BaseSuite.test/pure.test.mjs +93 -1146
  301. package/testeranto/bundles/python/core/Calculator.pitono.test.py +24 -0
  302. package/testeranto/bundles/python/core/test_example.py +24 -0
  303. package/testeranto/bundles/web/core/MPLUSRounded1c-Black-O75GP5JI.ttf +0 -0
  304. package/testeranto/bundles/web/core/MPLUSRounded1c-Bold-R524Q5BH.ttf +0 -0
  305. package/testeranto/bundles/web/core/MPLUSRounded1c-ExtraBold-C6GRMYVT.ttf +0 -0
  306. package/testeranto/bundles/web/core/MPLUSRounded1c-Light-WKN65Y2C.ttf +0 -0
  307. package/testeranto/bundles/web/core/MPLUSRounded1c-Medium-ZC4DWL7C.ttf +0 -0
  308. package/testeranto/bundles/web/core/MPLUSRounded1c-Regular-DT6EKZ3S.ttf +0 -0
  309. package/testeranto/bundles/web/core/MPLUSRounded1c-Thin-YWDNVG6M.ttf +0 -0
  310. package/testeranto/bundles/web/core/chunk-DFRN4SYZ.mjs +2297 -0
  311. package/testeranto/bundles/web/core/chunk-JMDLMADH.mjs +27996 -0
  312. package/testeranto/bundles/web/core/chunk-LQMU5NCG.mjs +3082 -0
  313. package/testeranto/bundles/web/core/chunk-Q5TONB2Z.mjs +6874 -0
  314. package/testeranto/bundles/web/core/src/components/pure/FeaturesReporterView.test/index.mjs +164 -0
  315. package/testeranto/bundles/web/core/src/components/pure/ModalContent.test/index.css +11697 -0
  316. package/testeranto/bundles/web/core/src/components/pure/ModalContent.test/index.mjs +336 -0
  317. package/testeranto/bundles/web/core/src/components/pure/ProjectPageView.test/index.css +11697 -0
  318. package/testeranto/bundles/web/core/src/components/pure/ProjectPageView.test/index.mjs +517 -0
  319. package/testeranto/bundles/web/core/src/lib/BaseSuite.test/web.test.mjs +107 -1134
  320. package/testeranto/metafiles/golang/core.json +3 -3
  321. package/testeranto/metafiles/node/core.json +474 -31
  322. package/testeranto/metafiles/pure/core.json +144 -28
  323. package/testeranto/metafiles/python/core.json +11 -0
  324. package/testeranto/metafiles/web/core.json +15829 -45
  325. package/testeranto/reports/core/config.json +40 -0
  326. package/testeranto/reports/core/src/Pure.test/pure/exit.log +0 -0
  327. package/testeranto/reports/core/src/Pure.test/pure/lint_errors.txt +0 -0
  328. package/testeranto/reports/core/src/Pure.test/pure/prompt.txt +14 -0
  329. package/testeranto/reports/core/src/Pure.test/pure/type_errors.txt +73 -0
  330. package/testeranto/reports/core/src/components/pure/FeaturesReporterView.test/index/web/debug.log +0 -0
  331. package/testeranto/reports/core/src/components/pure/FeaturesReporterView.test/index/web/error.log +91 -0
  332. package/testeranto/reports/core/src/components/pure/FeaturesReporterView.test/index/web/exit.log +1 -0
  333. package/testeranto/reports/core/src/components/pure/FeaturesReporterView.test/index/web/info.log +2 -0
  334. package/testeranto/reports/core/src/components/pure/FeaturesReporterView.test/index/web/tests.json +68 -0
  335. package/testeranto/reports/core/src/components/pure/FeaturesReporterView.test/index/web/warn.log +0 -0
  336. package/testeranto/reports/core/src/components/pure/ProjectPageView.test/index/web/debug.log +0 -0
  337. package/testeranto/reports/core/src/components/pure/ProjectPageView.test/index/web/error.log +30 -0
  338. package/testeranto/reports/core/src/components/pure/ProjectPageView.test/index/web/exit.log +1 -0
  339. package/testeranto/reports/core/src/components/pure/ProjectPageView.test/index/web/info.log +2 -0
  340. package/testeranto/reports/core/src/components/pure/ProjectPageView.test/index/web/tests.json +88 -0
  341. package/testeranto/reports/core/src/components/pure/ProjectPageView.test/index/web/warn.log +0 -0
  342. package/testeranto/reports/core/src/lib/BaseSuite.test/node.test/node/lint_errors.txt +0 -6
  343. package/testeranto/reports/core/src/lib/BaseSuite.test/node.test/node/prompt.txt +0 -11
  344. package/testeranto/reports/core/src/lib/BaseSuite.test/node.test/node/stdout.log +1 -0
  345. package/testeranto/reports/core/src/lib/BaseSuite.test/node.test/node/tests.json +1 -1
  346. package/testeranto/reports/core/src/lib/BaseSuite.test/node.test/node/type_errors.txt +35 -38
  347. package/testeranto/reports/core/src/lib/BaseSuite.test/pure.test/pure/lint_errors.txt +0 -2
  348. package/testeranto/reports/core/src/lib/BaseSuite.test/pure.test/pure/prompt.txt +0 -10
  349. package/testeranto/reports/core/src/lib/BaseSuite.test/pure.test/pure/type_errors.txt +40 -38
  350. package/testeranto/reports/core/src/lib/BaseSuite.test/web.test/web/tests.json +1 -1
  351. package/testeranto/reports/core/src/lib/TipoSkripto.test/TipoSkripto/node/exit.log +1 -0
  352. package/testeranto/reports/core/src/lib/TipoSkripto.test/TipoSkripto/node/lint_errors.txt +0 -0
  353. package/testeranto/reports/core/src/lib/TipoSkripto.test/TipoSkripto/node/message.txt +17 -0
  354. package/testeranto/reports/core/src/lib/TipoSkripto.test/TipoSkripto/node/prompt.txt +17 -0
  355. package/testeranto/reports/core/src/lib/TipoSkripto.test/TipoSkripto/node/stderr.log +55 -0
  356. package/testeranto/reports/core/src/lib/TipoSkripto.test/TipoSkripto/node/stdout.log +191 -0
  357. package/testeranto/reports/core/src/lib/TipoSkripto.test/TipoSkripto/node/type_errors.txt +71 -0
  358. package/testeranto/reports/core/src/lib/pmProxy.test/index/node/exit.log +1 -0
  359. package/testeranto/reports/core/src/lib/pmProxy.test/index/node/lint_errors.txt +15 -0
  360. package/testeranto/reports/core/src/lib/pmProxy.test/index/node/message.txt +17 -0
  361. package/testeranto/reports/core/src/lib/pmProxy.test/index/node/prompt.txt +17 -0
  362. package/testeranto/reports/core/src/lib/pmProxy.test/index/node/stderr.log +20 -0
  363. package/testeranto/reports/core/src/lib/pmProxy.test/index/node/stdout.log +4 -0
  364. package/testeranto/reports/core/src/lib/pmProxy.test/index/node/type_errors.txt +49 -0
  365. package/testeranto/reports/core/summary.json +34 -6
  366. package/testeranto.config.ts +26 -20
  367. package/tsc.log +141 -91
  368. package/tsconfig.json +6 -2
  369. package/dist/prebuild/ReportServer.mjs +0 -227
  370. package/dist/prebuild/mothership/index.mjs +0 -22
  371. package/dist/types/design-editor/server.d.ts +0 -1
  372. package/testeranto/bundles/web/core/src/lib/BaseSuite.test/web.test.html +0 -15
  373. package/testeranto/reports/core/src/lib/BaseSuite.test/web.test/web/lint_errors.txt +0 -2
  374. package/testeranto/reports/core/src/lib/BaseSuite.test/web.test/web/prompt.txt +0 -25
  375. package/testeranto/reports/core/src/lib/BaseSuite.test/web.test/web/type_errors.txt +0 -56
  376. /package/testeranto/reports/core/src/{lib/BaseSuite.test/web.test/web → Pure.test/pure}/message.txt +0 -0
@@ -1,38 +1,21 @@
1
1
  /* eslint-disable @typescript-eslint/no-unused-vars */
2
2
  /* eslint-disable @typescript-eslint/no-explicit-any */
3
- import React, { ReactElement, useState, useMemo, useEffect } from "react";
4
- import { Toast, ToastContainer } from "react-bootstrap";
3
+
4
+ import React, { useState, useEffect } from "react";
5
5
  import { useNavigate } from "react-router-dom";
6
+ import { useWebSocket } from "../../App";
6
7
  import {
7
8
  RuntimeName,
8
9
  STANDARD_LOGS,
9
- RUNTIME_SPECIFIC_LOGS
10
+ RUNTIME_SPECIFIC_LOGS,
10
11
  } from "../../utils/logFiles";
11
- import { Container, Row, Col, Nav, Button, Modal } from "react-bootstrap";
12
+ import { Container, Row, Col, Button, Modal } from "react-bootstrap";
12
13
  import { Editor } from "@monaco-editor/react";
13
14
  import { NavBar } from "./NavBar";
14
- import { TestStatusBadge } from "../TestStatusBadge";
15
-
16
- type TestData = {
17
- name: string;
18
- givens: {
19
- name: string;
20
- whens: {
21
- name: string;
22
- error?: string;
23
- features?: string[];
24
- artifacts?: string[];
25
- }[];
26
- thens: {
27
- name: string;
28
- error?: string;
29
- features?: string[];
30
- artifacts?: string[];
31
- }[];
32
- features?: string[];
33
- artifacts?: string[];
34
- }[];
35
- };
15
+ import { FileTreeItem } from "./FileTreeItem";
16
+ import { FileTree } from "./FileTree";
17
+ import { ToastNotification } from "./ToastNotification";
18
+ import { getLanguage, renderTestResults } from "./TestPageView_utils";
36
19
 
37
20
  type TestPageViewProps = {
38
21
  projectName: string;
@@ -46,61 +29,7 @@ type TestPageViewProps = {
46
29
  typeErrors: number;
47
30
  staticErrors: number;
48
31
  };
49
- };
50
-
51
- const FileTree = ({ data, onSelect, level = 0, selectedSourcePath }) => {
52
- const [expanded, setExpanded] = useState({});
53
-
54
- const toggleExpand = (path) => {
55
- setExpanded((prev) => ({ ...prev, [path]: !prev[path] }));
56
- };
57
-
58
- return (
59
- <div>
60
- {Object.entries(data).map(([name, node]) => {
61
- const path = Object.keys(expanded).find((k) => k.endsWith(name)) || name;
62
- const isExpanded = expanded[path];
63
-
64
- if (node.__isFile) {
65
- return (
66
- <FileTreeItem
67
- key={name}
68
- name={name}
69
- isFile={true}
70
- level={level}
71
- isSelected={selectedSourcePath === path}
72
- onClick={() => onSelect(path, node.content)}
73
- />
74
- );
75
- } else {
76
- return (
77
- <div key={name}>
78
- <div
79
- className="d-flex align-items-center py-1 text-dark"
80
- style={{
81
- paddingLeft: `${level * 16}px`,
82
- cursor: 'pointer',
83
- fontSize: '0.875rem'
84
- }}
85
- onClick={() => toggleExpand(path)}
86
- >
87
- <i className={`bi ${isExpanded ? 'bi-folder2-open' : 'bi-folder'} me-1`}></i>
88
- <span>{name}</span>
89
- </div>
90
- {isExpanded && (
91
- <FileTree
92
- data={node}
93
- onSelect={onSelect}
94
- level={level + 1}
95
- selectedSourcePath={selectedSourcePath}
96
- />
97
- )}
98
- </div>
99
- );
100
- }
101
- })}
102
- </div>
103
- );
32
+ isWebSocketConnected: boolean;
104
33
  };
105
34
 
106
35
  export const TestPageView = ({
@@ -111,17 +40,23 @@ export const TestPageView = ({
111
40
  testsExist,
112
41
  errorCounts,
113
42
  logs,
43
+ isWebSocketConnected,
114
44
  }: TestPageViewProps) => {
115
45
  const navigate = useNavigate();
116
46
  const [showAiderModal, setShowAiderModal] = useState(false);
117
- const [messageOption, setMessageOption] = useState<'default' | 'custom'>('default');
47
+ const [messageOption, setMessageOption] = useState<"default" | "custom">(
48
+ "default"
49
+ );
118
50
  const [customMessage, setCustomMessage] = useState(
119
- typeof logs['message.txt'] === 'string' ? logs['message.txt'] : 'make a script that prints hello'
51
+ typeof logs["message.txt"] === "string"
52
+ ? logs["message.txt"]
53
+ : "make a script that prints hello"
120
54
  );
121
55
  const [showToast, setShowToast] = useState(false);
122
- const [toastMessage, setToastMessage] = useState('');
123
- const [toastVariant, setToastVariant] = useState<'success' | 'danger'>('success');
124
- const [ws, setWs] = useState<WebSocket | null>(null);
56
+ const [toastMessage, setToastMessage] = useState("");
57
+ const [toastVariant, setToastVariant] = useState<"success" | "danger">(
58
+ "success"
59
+ );
125
60
  const [expandedSections, setExpandedSections] = useState({
126
61
  standardLogs: true,
127
62
  runtimeLogs: true,
@@ -131,7 +66,10 @@ export const TestPageView = ({
131
66
  const [isNavbarCollapsed, setIsNavbarCollapsed] = useState(false);
132
67
 
133
68
  // Extract build errors and warnings relevant to this test
134
- const [buildErrors, setBuildErrors] = useState<{ errors: any[]; warnings: any[] }>({ errors: [], warnings: [] });
69
+ const [buildErrors, setBuildErrors] = useState<{
70
+ errors: any[];
71
+ warnings: any[];
72
+ }>({ errors: [], warnings: [] });
135
73
 
136
74
  useEffect(() => {
137
75
  const metafile = logs.build_logs?.metafile;
@@ -143,46 +81,44 @@ export const TestPageView = ({
143
81
  // Collect all input files from metafile outputs related to this test
144
82
  Object.entries(metafile.outputs || {}).forEach(([outputPath, output]) => {
145
83
  // Normalize paths for comparison
146
- const normalizedTestName = testName.replace(/\\/g, '/');
147
- const normalizedEntryPoint = output.entryPoint ? output.entryPoint.replace(/\\/g, '/') : '';
84
+ const normalizedTestName = testName.replace(/\\/g, "/");
85
+ const normalizedEntryPoint = output.entryPoint
86
+ ? output.entryPoint.replace(/\\/g, "/")
87
+ : "";
148
88
  if (normalizedEntryPoint.includes(normalizedTestName)) {
149
89
  Object.keys(output.inputs || {}).forEach((inputPath) => {
150
- sourceFilesSet.add(inputPath.replace(/\\/g, '/'));
90
+ sourceFilesSet.add(inputPath.replace(/\\/g, "/"));
151
91
  });
152
92
  }
153
93
  });
154
94
 
155
95
  // Filter errors and warnings to those originating from source files of this test
156
- const filteredErrors = (logs.build_logs?.errors || []).filter((err: any) => {
157
- if (!err.location || !err.location.file) return false;
158
- return sourceFilesSet.has(err.location.file.replace(/\\/g, '/'));
159
- });
160
- const filteredWarnings = (logs.build_logs?.warnings || []).filter((warn: any) => {
161
- if (!warn.location || !warn.location.file) return false;
162
- return sourceFilesSet.has(warn.location.file.replace(/\\/g, '/'));
163
- });
96
+ const filteredErrors = (logs.build_logs?.errors || []).filter(
97
+ (err: any) => {
98
+ if (!err.location || !err.location.file) return false;
99
+ return sourceFilesSet.has(err.location.file.replace(/\\/g, "/"));
100
+ }
101
+ );
102
+ const filteredWarnings = (logs.build_logs?.warnings || []).filter(
103
+ (warn: any) => {
104
+ if (!warn.location || !warn.location.file) return false;
105
+ return sourceFilesSet.has(warn.location.file.replace(/\\/g, "/"));
106
+ }
107
+ );
164
108
 
165
109
  setBuildErrors({ errors: filteredErrors, warnings: filteredWarnings });
166
110
  }, [logs, testName]);
167
111
 
168
112
  // Update customMessage when logs change
169
113
  useEffect(() => {
170
- if (typeof logs['message.txt'] === 'string' && logs['message.txt'].trim()) {
171
- setCustomMessage(logs['message.txt']);
114
+ if (typeof logs["message.txt"] === "string" && logs["message.txt"].trim()) {
115
+ setCustomMessage(logs["message.txt"]);
172
116
  }
173
117
  }, [logs]);
174
118
 
175
- // Set up WebSocket connection
176
- useEffect(() => {
177
- const wsProtocol = window.location.protocol === 'https:' ? 'wss:' : 'ws:';
178
- const wsUrl = `${wsProtocol}//${window.location.host}`;
179
- const websocket = new WebSocket(wsUrl);
180
- setWs(websocket);
181
-
182
- return () => {
183
- websocket.close();
184
- };
185
- }, []);
119
+ // Use the centralized WebSocket from App context
120
+ const wsContext = useWebSocket();
121
+ const ws = wsContext?.ws;
186
122
  const [activeTab, setActiveTab] = React.useState("tests.json");
187
123
  const [selectedFile, setSelectedFile] = useState<{
188
124
  path: string;
@@ -196,271 +132,6 @@ export const TestPageView = ({
196
132
  "vs-dark"
197
133
  );
198
134
 
199
- // Determine language from file extension
200
- const getLanguage = (path: string) => {
201
- const ext = path.split(".").pop()?.toLowerCase();
202
- switch (ext) {
203
- case "ts":
204
- return "typescript";
205
- case "tsx":
206
- return "typescript";
207
- case "js":
208
- return "javascript";
209
- case "json":
210
- return "json";
211
- case "md":
212
- return "markdown";
213
- default:
214
- return "plaintext";
215
- }
216
- };
217
-
218
- const renderTestResults = (testData: TestData) => {
219
- return (
220
- <div className="test-results">
221
- {testData.givens.map((given, i) => (
222
- <div key={i} className="mb-4 card">
223
- <div className="card-header bg-primary text-white">
224
- <div className="d-flex justify-content-between align-items-center">
225
- <div>
226
- <h4>Given: {given.name}</h4>
227
- {given.features && given.features.length > 0 && (
228
- <div className="mt-1">
229
- <small>Features:</small>
230
- <ul className="list-unstyled">
231
- {given.features.map((feature, fi) => (
232
- <li key={fi}>
233
- {feature.startsWith("http") ? (
234
- <a
235
- href={feature}
236
- target="_blank"
237
- rel="noopener noreferrer"
238
- className="text-white"
239
- >
240
- {new URL(feature).hostname}
241
- </a>
242
- ) : (
243
- <span className="text-white">{feature}</span>
244
- )}
245
- </li>
246
- ))}
247
- </ul>
248
- </div>
249
- )}
250
- </div>
251
- {given.artifacts && given.artifacts.length > 0 && (
252
- <div className="dropdown">
253
- <button
254
- className="btn btn-sm btn-light dropdown-toggle"
255
- type="button"
256
- data-bs-toggle="dropdown"
257
- >
258
- Artifacts ({given.artifacts.length})
259
- </button>
260
- <ul className="dropdown-menu dropdown-menu-end">
261
- {given.artifacts.map((artifact, ai) => (
262
- <li key={ai}>
263
- <a
264
- className="dropdown-item"
265
- href={`reports/${projectName}/${testName
266
- .split(".")
267
- .slice(0, -1)
268
- .join(".")}/${runtime}/${artifact}`}
269
- target="_blank"
270
- rel="noopener noreferrer"
271
- >
272
- {artifact.split("/").pop()}
273
- </a>
274
- </li>
275
- ))}
276
- </ul>
277
- </div>
278
- )}
279
- </div>
280
- </div>
281
- <div className="card-body">
282
- {given.whens.map((when, j) => (
283
- <div
284
- key={`w-${j}`}
285
- className={`p-3 mb-2 ${when.error
286
- ? "bg-danger text-white"
287
- : "bg-success text-white"
288
- }`}
289
- >
290
- <div className="d-flex justify-content-between align-items-start">
291
- <div>
292
- <div>
293
- <strong>When:</strong> {when.name}
294
- {when.features && when.features.length > 0 && (
295
- <div className="mt-2">
296
- <small>Features:</small>
297
- <ul className="list-unstyled">
298
- {when.features.map((feature, fi) => (
299
- <li key={fi}>
300
- {feature.startsWith("http") ? (
301
- <a
302
- href={feature}
303
- target="_blank"
304
- rel="noopener noreferrer"
305
- >
306
- {new URL(feature).hostname}
307
- </a>
308
- ) : (
309
- feature
310
- )}
311
- </li>
312
- ))}
313
- </ul>
314
- </div>
315
- )}
316
- {when.error && <pre className="mt-2">{when.error}</pre>}
317
- </div>
318
- </div>
319
- {when.artifacts && when.artifacts.length > 0 && (
320
- <div className="ms-3">
321
- <strong>Artifacts:</strong>
322
- <ul className="list-unstyled">
323
- {when.artifacts.map((artifact, ai) => (
324
- <li key={ai}>
325
- <a
326
- href={`reports/${projectName}/${testName
327
- .split(".")
328
- .slice(0, -1)
329
- .join(".")}/${runtime}/${artifact}`}
330
- target="_blank"
331
- className="text-white"
332
- rel="noopener noreferrer"
333
- >
334
- {artifact.split("/").pop()}
335
- </a>
336
- </li>
337
- ))}
338
- </ul>
339
- </div>
340
- )}
341
- </div>
342
- </div>
343
- ))}
344
- {given.thens.map((then, k) => (
345
- <div
346
- key={`t-${k}`}
347
- className={`p-3 mb-2 ${then.error
348
- ? "bg-danger text-white"
349
- : "bg-success text-white"
350
- }`}
351
- >
352
- <div className="d-flex justify-content-between align-items-start">
353
- <div>
354
- <div>
355
- <strong>Then:</strong> {then.name}
356
- {then.features && then.features.length > 0 && (
357
- <div className="mt-2">
358
- <small>Features:</small>
359
- <ul className="list-unstyled">
360
- {then.features.map((feature, fi) => (
361
- <li key={fi}>
362
- {feature.startsWith("http") ? (
363
- <a
364
- href={feature}
365
- target="_blank"
366
- rel="noopener noreferrer"
367
- >
368
- {new URL(feature).hostname}
369
- </a>
370
- ) : (
371
- feature
372
- )}
373
- </li>
374
- ))}
375
- </ul>
376
- </div>
377
- )}
378
- {then.error && <pre className="mt-2">{then.error}</pre>}
379
- </div>
380
- </div>
381
- {then.artifacts && then.artifacts.length > 0 && (
382
- <div className="ms-3">
383
- <strong>Artifacts:</strong>
384
- <ul className="list-unstyled">
385
- {then.artifacts.map((artifact, ai) => (
386
- <li key={ai}>
387
- <a
388
- href={`reports/${projectName}/${testName
389
- .split(".")
390
- .slice(0, -1)
391
- .join(".")}/${runtime}/${artifact}`}
392
- target="_blank"
393
- className="text-white"
394
- rel="noopener noreferrer"
395
- >
396
- {artifact.split("/").pop()}
397
- </a>
398
- </li>
399
- ))}
400
- </ul>
401
- </div>
402
- )}
403
- </div>
404
- </div>
405
- ))}
406
- </div>
407
- </div>
408
- ))}
409
- {/* Render build errors and warnings */}
410
- {(buildErrors.errors.length > 0 || buildErrors.warnings.length > 0) && (
411
- <div className="mb-4 card border-danger">
412
- <div className="card-header bg-danger text-white">
413
- <h4>Build Errors and Warnings</h4>
414
- </div>
415
- <div className="card-body">
416
- {buildErrors.errors.length > 0 && (
417
- <>
418
- <h5>Errors</h5>
419
- <ul>
420
- {buildErrors.errors.map((error, idx) => (
421
- <li key={`build-error-${idx}`}>
422
- <strong>{error.text}</strong>
423
- {error.location && (
424
- <div>
425
- File: {error.location.file} Line: {error.location.line} Column: {error.location.column}
426
- </div>
427
- )}
428
- </li>
429
- ))}
430
- </ul>
431
- </>
432
- )}
433
- {buildErrors.warnings.length > 0 && (
434
- <>
435
- <h5>Warnings</h5>
436
- <ul>
437
- {buildErrors.warnings.map((warning, idx) => (
438
- <li key={`build-warning-${idx}`}>
439
- <strong>{warning.text}</strong>
440
- {warning.location && (
441
- <div>
442
- File: {warning.location.file} Line: {warning.location.line} Column: {warning.location.column}
443
- </div>
444
- )}
445
- </li>
446
- ))}
447
- </ul>
448
- </>
449
- )}
450
- </div>
451
- </div>
452
- )}
453
- </div>
454
- );
455
- };
456
-
457
- console.log("Rendering TestPageView with logs:", {
458
- logKeys: Object.keys(logs),
459
- sourceFiles: logs.source_files ? Object.keys(logs.source_files) : null,
460
- selectedFile,
461
- activeTab,
462
- });
463
-
464
135
  return (
465
136
  <Container fluid className="px-0">
466
137
  <NavBar
@@ -485,22 +156,38 @@ export const TestPageView = ({
485
156
  <Button
486
157
  variant="info"
487
158
  onClick={() => setShowAiderModal(true)}
488
- className="ms-2"
489
- title="AI Assistant"
159
+ className="ms-2 position-relative"
160
+ title={
161
+ isWebSocketConnected
162
+ ? "AI Assistant"
163
+ : "AI Assistant (WebSocket not connected)"
164
+ }
165
+ disabled={!isWebSocketConnected}
490
166
  >
491
167
  🤖
168
+ {!isWebSocketConnected && (
169
+ <span
170
+ className="position-absolute top-0 start-100 translate-middle p-1 bg-danger border border-light rounded-circle"
171
+ title="WebSocket disconnected"
172
+ >
173
+ <span className="visually-hidden">WebSocket disconnected</span>
174
+ </span>
175
+ )}
492
176
  </Button>
493
177
  }
494
178
  />
495
179
 
496
- <Modal show={showAiderModal} onHide={() => setShowAiderModal(false)} size="lg" onShow={() => setMessageOption('default')}>
180
+ <Modal
181
+ show={showAiderModal}
182
+ onHide={() => setShowAiderModal(false)}
183
+ size="lg"
184
+ onShow={() => setMessageOption("default")}
185
+ >
497
186
  <Modal.Header closeButton>
498
187
  <Modal.Title>Aider</Modal.Title>
499
188
  </Modal.Header>
500
189
  <Modal.Body>
501
-
502
190
  <div className="mb-3">
503
-
504
191
  <div className="form-check">
505
192
  <input
506
193
  className="form-check-input"
@@ -508,8 +195,8 @@ export const TestPageView = ({
508
195
  name="messageOption"
509
196
  id="defaultMessage"
510
197
  value="default"
511
- checked={messageOption === 'default'}
512
- onChange={() => setMessageOption('default')}
198
+ checked={messageOption === "default"}
199
+ onChange={() => setMessageOption("default")}
513
200
  />
514
201
  <label className="form-check-label" htmlFor="defaultMessage">
515
202
  Use default message.txt
@@ -522,14 +209,14 @@ export const TestPageView = ({
522
209
  name="messageOption"
523
210
  id="customMessage"
524
211
  value="custom"
525
- checked={messageOption === 'custom'}
526
- onChange={() => setMessageOption('custom')}
212
+ checked={messageOption === "custom"}
213
+ onChange={() => setMessageOption("custom")}
527
214
  />
528
215
  <label className="form-check-label" htmlFor="customMessage">
529
216
  Use custom message
530
217
  </label>
531
218
  </div>
532
- {messageOption === 'custom' && (
219
+ {messageOption === "custom" && (
533
220
  <div className="mt-2">
534
221
  <textarea
535
222
  className="form-control"
@@ -537,7 +224,7 @@ export const TestPageView = ({
537
224
  placeholder="Enter your custom message"
538
225
  value={customMessage}
539
226
  onChange={(e) => setCustomMessage(e.target.value)}
540
- style={{ minHeight: '500px' }}
227
+ style={{ minHeight: "500px" }}
541
228
  />
542
229
  </div>
543
230
  )}
@@ -561,7 +248,7 @@ export const TestPageView = ({
561
248
 
562
249
  let command = `aider --load ${promptPath}`;
563
250
 
564
- if (messageOption === 'default') {
251
+ if (messageOption === "default") {
565
252
  const messagePath = `testeranto/reports/${projectName}/${testName
566
253
  .split(".")
567
254
  .slice(0, -1)
@@ -571,34 +258,32 @@ export const TestPageView = ({
571
258
  command += ` --message "${customMessage}"`;
572
259
  }
573
260
 
574
- // Send command to server via WebSocket
575
- const ws = new WebSocket(`ws://${window.location.host}`);
576
- ws.onopen = () => {
577
- ws.send(JSON.stringify({
578
- type: 'executeCommand',
579
- command: command
580
- }));
581
- setToastMessage('Command sent to server');
582
- setToastVariant('success');
261
+ // Send command to server via the centralized WebSocket
262
+ if (isWebSocketConnected && ws) {
263
+ ws.send(
264
+ JSON.stringify({
265
+ type: "executeCommand",
266
+ command: command,
267
+ })
268
+ );
269
+ setToastMessage("Command sent to server");
270
+ setToastVariant("success");
583
271
  setShowToast(true);
584
272
  setShowAiderModal(false);
585
- ws.close();
586
273
 
587
274
  // Navigate to process manager page
588
275
  setTimeout(() => {
589
- navigate('/processes');
276
+ navigate("/processes");
590
277
  }, 1000);
591
- };
592
-
593
- ws.onerror = (error) => {
594
- setToastMessage('Failed to connect to server');
595
- setToastVariant('danger');
278
+ } else {
279
+ setToastMessage("WebSocket connection not ready");
280
+ setToastVariant("danger");
596
281
  setShowToast(true);
597
- };
282
+ }
598
283
  } catch (err) {
599
284
  console.error("WebSocket error:", err);
600
- setToastMessage('Error preparing command');
601
- setToastVariant('danger');
285
+ setToastMessage("Error preparing command");
286
+ setToastVariant("danger");
602
287
  setShowToast(true);
603
288
  }
604
289
  }}
@@ -609,11 +294,15 @@ export const TestPageView = ({
609
294
  </Modal>
610
295
 
611
296
  <Row className="g-0">
612
- <Col sm={3} className="border-end" style={{
613
- height: "calc(100vh - 56px)",
614
- overflow: "auto",
615
- backgroundColor: '#f8f9fa'
616
- }}>
297
+ <Col
298
+ sm={3}
299
+ className="border-end"
300
+ style={{
301
+ height: "calc(100vh - 56px)",
302
+ overflow: "auto",
303
+ backgroundColor: "#f8f9fa",
304
+ }}
305
+ >
617
306
  {/* File Tree Header */}
618
307
  <div className="p-2 border-bottom">
619
308
  <small className="fw-bold text-muted">EXPLORER</small>
@@ -623,19 +312,31 @@ export const TestPageView = ({
623
312
  <div className="p-2">
624
313
  <div
625
314
  className="d-flex align-items-center text-muted mb-1"
626
- style={{ cursor: 'pointer', fontSize: '0.875rem' }}
627
- onClick={() => setExpandedSections(prev => ({ ...prev, standardLogs: !prev.standardLogs }))}
315
+ style={{ cursor: "pointer", fontSize: "0.875rem" }}
316
+ onClick={() =>
317
+ setExpandedSections((prev) => ({
318
+ ...prev,
319
+ standardLogs: !prev.standardLogs,
320
+ }))
321
+ }
628
322
  >
629
- <i className={`bi bi-chevron-${expandedSections.standardLogs ? 'down' : 'right'} me-1`}></i>
323
+ <i
324
+ className={`bi bi-chevron-${expandedSections.standardLogs ? "down" : "right"
325
+ } me-1`}
326
+ ></i>
630
327
  <span>Standard Logs</span>
631
328
  </div>
632
329
  {expandedSections.standardLogs && (
633
330
  <div>
634
331
  {Object.values(STANDARD_LOGS).map((logName) => {
635
332
  const logContent = logs ? logs[logName] : undefined;
636
- const exists = logContent !== undefined &&
637
- ((typeof logContent === "string" && logContent.trim() !== "") ||
638
- (typeof logContent === "object" && logContent !== null && Object.keys(logContent).length > 0));
333
+ const exists =
334
+ logContent !== undefined &&
335
+ ((typeof logContent === "string" &&
336
+ logContent.trim() !== "") ||
337
+ (typeof logContent === "object" &&
338
+ logContent !== null &&
339
+ Object.keys(logContent).length > 0));
639
340
 
640
341
  return (
641
342
  <FileTreeItem
@@ -650,8 +351,13 @@ export const TestPageView = ({
650
351
  setActiveTab(logName);
651
352
  setSelectedFile({
652
353
  path: logName,
653
- content: typeof logContent === "string" ? logContent : JSON.stringify(logContent, null, 2),
654
- language: logName.endsWith(".json") ? "json" : "plaintext",
354
+ content:
355
+ typeof logContent === "string"
356
+ ? logContent
357
+ : JSON.stringify(logContent, null, 2),
358
+ language: logName.endsWith(".json")
359
+ ? "json"
360
+ : "plaintext",
655
361
  });
656
362
  } else {
657
363
  setActiveTab(logName);
@@ -670,67 +376,96 @@ export const TestPageView = ({
670
376
  </div>
671
377
 
672
378
  {/* Runtime Logs Section */}
673
- {runtime && RUNTIME_SPECIFIC_LOGS[runtime as RuntimeName] &&
674
- Object.values(RUNTIME_SPECIFIC_LOGS[runtime as RuntimeName]).length > 0 && (
675
- <div className="p-2">
676
- <div
677
- className="d-flex align-items-center text-muted mb-1"
678
- style={{ cursor: 'pointer', fontSize: '0.875rem' }}
679
- onClick={() => setExpandedSections(prev => ({ ...prev, runtimeLogs: !prev.runtimeLogs }))}
680
- >
681
- <i className={`bi bi-chevron-${expandedSections.runtimeLogs ? 'down' : 'right'} me-1`}></i>
682
- <span>Runtime Logs</span>
683
- </div>
684
- {expandedSections.runtimeLogs && (
685
- <div>
686
- {Object.values(RUNTIME_SPECIFIC_LOGS[runtime as RuntimeName]).map((logName) => {
687
- const logContent = logs ? logs[logName] : undefined;
688
- const exists = logContent !== undefined &&
689
- ((typeof logContent === "string" && logContent.trim() !== "") ||
690
- (typeof logContent === "object" && logContent !== null && Object.keys(logContent).length > 0));
691
-
692
- return (
693
- <FileTreeItem
694
- key={logName}
695
- name={logName}
696
- isFile={true}
697
- level={1}
698
- isSelected={activeTab === logName}
699
- exists={exists}
700
- onClick={() => {
701
- if (exists) {
702
- setActiveTab(logName);
703
- setSelectedFile({
704
- path: logName,
705
- content: typeof logContent === "string" ? logContent : JSON.stringify(logContent, null, 2),
706
- language: logName.endsWith(".json") ? "json" : "plaintext",
707
- });
708
- } else {
709
- setActiveTab(logName);
710
- setSelectedFile({
711
- path: logName,
712
- content: `// ${logName} not found or empty\nThis file was not generated during the test run.`,
713
- language: "plaintext",
714
- });
715
- }
716
- }}
717
- />
718
- );
719
- })}
379
+ {runtime &&
380
+ RUNTIME_SPECIFIC_LOGS[runtime as RuntimeName] &&
381
+ Object.values(RUNTIME_SPECIFIC_LOGS[runtime as RuntimeName])
382
+ .length > 0 && (
383
+ <div className="p-2">
384
+ <div
385
+ className="d-flex align-items-center text-muted mb-1"
386
+ style={{ cursor: "pointer", fontSize: "0.875rem" }}
387
+ onClick={() =>
388
+ setExpandedSections((prev) => ({
389
+ ...prev,
390
+ runtimeLogs: !prev.runtimeLogs,
391
+ }))
392
+ }
393
+ >
394
+ <i
395
+ className={`bi bi-chevron-${expandedSections.runtimeLogs ? "down" : "right"
396
+ } me-1`}
397
+ ></i>
398
+ <span>Runtime Logs</span>
720
399
  </div>
721
- )}
722
- </div>
723
- )}
400
+ {expandedSections.runtimeLogs && (
401
+ <div>
402
+ {Object.values(
403
+ RUNTIME_SPECIFIC_LOGS[runtime as RuntimeName]
404
+ ).map((logName) => {
405
+ const logContent = logs ? logs[logName] : undefined;
406
+ const exists =
407
+ logContent !== undefined &&
408
+ ((typeof logContent === "string" &&
409
+ logContent.trim() !== "") ||
410
+ (typeof logContent === "object" &&
411
+ logContent !== null &&
412
+ Object.keys(logContent).length > 0));
413
+
414
+ return (
415
+ <FileTreeItem
416
+ key={logName}
417
+ name={logName}
418
+ isFile={true}
419
+ level={1}
420
+ isSelected={activeTab === logName}
421
+ exists={exists}
422
+ onClick={() => {
423
+ if (exists) {
424
+ setActiveTab(logName);
425
+ setSelectedFile({
426
+ path: logName,
427
+ content:
428
+ typeof logContent === "string"
429
+ ? logContent
430
+ : JSON.stringify(logContent, null, 2),
431
+ language: logName.endsWith(".json")
432
+ ? "json"
433
+ : "plaintext",
434
+ });
435
+ } else {
436
+ setActiveTab(logName);
437
+ setSelectedFile({
438
+ path: logName,
439
+ content: `// ${logName} not found or empty\nThis file was not generated during the test run.`,
440
+ language: "plaintext",
441
+ });
442
+ }
443
+ }}
444
+ />
445
+ );
446
+ })}
447
+ </div>
448
+ )}
449
+ </div>
450
+ )}
724
451
 
725
452
  {/* Source Files Section */}
726
453
  {logs && logs.source_files && (
727
454
  <div className="p-2">
728
455
  <div
729
456
  className="d-flex align-items-center text-muted mb-1"
730
- style={{ cursor: 'pointer', fontSize: '0.875rem' }}
731
- onClick={() => setExpandedSections(prev => ({ ...prev, sourceFiles: !prev.sourceFiles }))}
457
+ style={{ cursor: "pointer", fontSize: "0.875rem" }}
458
+ onClick={() =>
459
+ setExpandedSections((prev) => ({
460
+ ...prev,
461
+ sourceFiles: !prev.sourceFiles,
462
+ }))
463
+ }
732
464
  >
733
- <i className={`bi bi-chevron-${expandedSections.sourceFiles ? 'down' : 'right'} me-1`}></i>
465
+ <i
466
+ className={`bi bi-chevron-${expandedSections.sourceFiles ? "down" : "right"
467
+ } me-1`}
468
+ ></i>
734
469
  <span>Source Files</span>
735
470
  </div>
736
471
  {expandedSections.sourceFiles && (
@@ -776,14 +511,29 @@ export const TestPageView = ({
776
511
  }}
777
512
  />
778
513
  </Col>
779
- <Col sm={3} className="p-0 border-start" style={{ height: "calc(100vh - 56px)", overflow: "auto" }}>
514
+ <Col
515
+ sm={3}
516
+ className="p-0 border-start"
517
+ style={{ height: "calc(100vh - 56px)", overflow: "auto" }}
518
+ >
780
519
  <div className="p-3">
781
520
  {selectedFile?.path.endsWith("tests.json") && (
782
521
  <div className="test-results-preview">
783
522
  {typeof selectedFile.content === "string"
784
- ? renderTestResults(JSON.parse(selectedFile.content))
785
- : renderTestResults(selectedFile.content)
786
- }
523
+ ? renderTestResults(
524
+ JSON.parse(selectedFile.content),
525
+ buildErrors,
526
+ projectName,
527
+ testName,
528
+ runtime
529
+ )
530
+ : renderTestResults(
531
+ selectedFile.content,
532
+ buildErrors,
533
+ projectName,
534
+ testName,
535
+ runtime
536
+ )}
787
537
  </div>
788
538
  )}
789
539
  {selectedFile?.path.match(/\.(png|jpg|jpeg|gif|svg)$/i) && (
@@ -792,7 +542,7 @@ export const TestPageView = ({
792
542
  src={selectedFile.content}
793
543
  alt={selectedFile.path}
794
544
  className="img-fluid"
795
- style={{ maxHeight: '300px' }}
545
+ style={{ maxHeight: "300px" }}
796
546
  />
797
547
  <div className="mt-2">
798
548
  <a
@@ -816,68 +566,93 @@ export const TestPageView = ({
816
566
  <>
817
567
  {buildData.errors?.length > 0 && (
818
568
  <div className="mb-3">
819
- <h6 className="text-danger">Errors ({buildData.errors.length})</h6>
569
+ <h6 className="text-danger">
570
+ Errors ({buildData.errors.length})
571
+ </h6>
820
572
  <ul className="list-unstyled">
821
- {buildData.errors.map((error: any, index: number) => (
822
- <li key={index} className="mb-2 p-2 bg-light rounded">
823
- <div className="text-danger fw-bold">{error.text}</div>
824
- {error.location && (
825
- <div className="small text-muted">
826
- File: {error.location.file}
827
- Line: {error.location.line}
828
- Column: {error.location.column}
573
+ {buildData.errors.map(
574
+ (error: any, index: number) => (
575
+ <li key={index} className="mb-2 p-2 rounded">
576
+ <div className="text-danger fw-bold">
577
+ {error.text}
829
578
  </div>
830
- )}
831
- {error.notes && error.notes.length > 0 && (
832
- <div className="small">
833
- Notes:
834
- <ul>
835
- {error.notes.map((note: any, noteIndex: number) => (
836
- <li key={noteIndex}>{note.text}</li>
837
- ))}
838
- </ul>
839
- </div>
840
- )}
841
- </li>
842
- ))}
579
+ {error.location && (
580
+ <div className="small text-muted">
581
+ File: {error.location.file}
582
+ Line: {error.location.line}
583
+ Column: {error.location.column}
584
+ </div>
585
+ )}
586
+ {error.notes && error.notes.length > 0 && (
587
+ <div className="small">
588
+ Notes:
589
+ <ul>
590
+ {error.notes.map(
591
+ (note: any, noteIndex: number) => (
592
+ <li key={noteIndex}>
593
+ {note.text}
594
+ </li>
595
+ )
596
+ )}
597
+ </ul>
598
+ </div>
599
+ )}
600
+ </li>
601
+ )
602
+ )}
843
603
  </ul>
844
604
  </div>
845
605
  )}
846
606
  {buildData.warnings?.length > 0 && (
847
607
  <div className="mb-3">
848
- <h6 className="text-warning">Warnings ({buildData.warnings.length})</h6>
608
+ <h6 className="text-warning">
609
+ Warnings ({buildData.warnings.length})
610
+ </h6>
849
611
  <ul className="list-unstyled">
850
- {buildData.warnings.map((warning: any, index: number) => (
851
- <li key={index} className="mb-2 p-2 bg-light rounded">
852
- <div className="text-warning fw-bold">{warning.text}</div>
853
- {warning.location && (
854
- <div className="small text-muted">
855
- File: {warning.location.file}
856
- Line: {warning.location.line}
857
- Column: {warning.location.column}
858
- </div>
859
- )}
860
- {warning.notes && warning.notes.length > 0 && (
861
- <div className="small">
862
- Notes:
863
- <ul>
864
- {warning.notes.map((note: any, noteIndex: number) => (
865
- <li key={noteIndex}>{note.text}</li>
866
- ))}
867
- </ul>
612
+ {buildData.warnings.map(
613
+ (warning: any, index: number) => (
614
+ <li key={index} className="mb-2 p-2 rounded">
615
+ <div className="text-warning fw-bold">
616
+ {warning.text}
868
617
  </div>
869
- )}
870
- </li>
871
- ))}
618
+ {warning.location && (
619
+ <div className="small text-muted">
620
+ File: {warning.location.file}
621
+ Line: {warning.location.line}
622
+ Column: {warning.location.column}
623
+ </div>
624
+ )}
625
+ {warning.notes &&
626
+ warning.notes.length > 0 && (
627
+ <div className="small">
628
+ Notes:
629
+ <ul>
630
+ {warning.notes.map(
631
+ (
632
+ note: any,
633
+ noteIndex: number
634
+ ) => (
635
+ <li key={noteIndex}>
636
+ {note.text}
637
+ </li>
638
+ )
639
+ )}
640
+ </ul>
641
+ </div>
642
+ )}
643
+ </li>
644
+ )
645
+ )}
872
646
  </ul>
873
647
  </div>
874
648
  )}
875
- {(!buildData.errors || buildData.errors.length === 0) &&
876
- (!buildData.warnings || buildData.warnings.length === 0) && (
877
- <div className="alert alert-success">
878
- No build errors or warnings
879
- </div>
880
- )}
649
+ {(!buildData.errors || buildData.errors.length === 0) &&
650
+ (!buildData.warnings ||
651
+ buildData.warnings.length === 0) && (
652
+ <div className="alert alert-success">
653
+ No build errors or warnings
654
+ </div>
655
+ )}
881
656
  </>
882
657
  );
883
658
  } catch (e) {
@@ -890,18 +665,18 @@ export const TestPageView = ({
890
665
  })()}
891
666
  </div>
892
667
  )}
893
- {selectedFile?.path.endsWith(".json") &&
894
- !selectedFile.path.endsWith("tests.json") &&
895
- !selectedFile.path.endsWith("build.json") && (
896
- <pre className="bg-light p-2 small">
897
- <code>{selectedFile.content}</code>
898
- </pre>
899
- )}
668
+ {selectedFile?.path.endsWith(".json") &&
669
+ !selectedFile.path.endsWith("tests.json") &&
670
+ !selectedFile.path.endsWith("build.json") && (
671
+ <pre className=" p-2 small">
672
+ <code>{selectedFile.content}</code>
673
+ </pre>
674
+ )}
900
675
  {selectedFile?.path.includes("source_files") && (
901
676
  <div>
902
677
  <div className="mb-2 small text-muted">
903
678
  <i className="bi bi-file-earmark-text me-1"></i>
904
- {selectedFile.path.split('/').pop()}
679
+ {selectedFile.path.split("/").pop()}
905
680
  </div>
906
681
  <Button
907
682
  variant="outline-primary"
@@ -920,296 +695,12 @@ export const TestPageView = ({
920
695
  </Col>
921
696
  </Row>
922
697
 
923
- <ToastContainer position="top-end" className="p-3">
924
- <Toast
925
- show={showToast}
926
- onClose={() => setShowToast(false)}
927
- delay={3000}
928
- autohide
929
- bg={toastVariant}
930
- >
931
- <Toast.Header>
932
- <strong className="me-auto">Command Status</strong>
933
- </Toast.Header>
934
- <Toast.Body className="text-white">
935
- {toastMessage}
936
- </Toast.Body>
937
- </Toast>
938
- </ToastContainer>
939
-
698
+ <ToastNotification
699
+ showToast={showToast}
700
+ setShowToast={setShowToast}
701
+ toastVariant={toastVariant}
702
+ toastMessage={toastMessage}
703
+ />
940
704
  </Container>
941
705
  );
942
706
  };
943
- // Simple file tree item component
944
- const FileTreeItem = ({
945
- name,
946
- isFile,
947
- level,
948
- isSelected,
949
- exists = true,
950
- onClick
951
- }: {
952
- name: string;
953
- isFile: boolean;
954
- level: number;
955
- isSelected: boolean;
956
- exists?: boolean;
957
- onClick: () => void;
958
- }) => {
959
- const displayName = name
960
- .replace(".json", "")
961
- .replace(".txt", "")
962
- .replace(".log", "")
963
- .replace(/_/g, " ")
964
- .replace(/^std/, "Standard ")
965
- .replace(/^exit/, "Exit Code")
966
- .split('/').pop();
967
-
968
- return (
969
- <div
970
- className={`d-flex align-items-center py-1 ${isSelected ? 'text-primary fw-bold' : exists ? 'text-dark' : 'text-muted'}`}
971
- style={{
972
- paddingLeft: `${level * 16}px`,
973
- cursor: exists ? 'pointer' : 'not-allowed',
974
- fontSize: '0.875rem',
975
- opacity: exists ? 1 : 0.6
976
- }}
977
- onClick={exists ? onClick : undefined}
978
- title={exists ? undefined : "File not found or empty"}
979
- >
980
- <i className={`bi ${isFile ? (exists ? 'bi-file-earmark-text' : 'bi-file-earmark') : 'bi-folder'} me-1`}></i>
981
- <span>{displayName}</span>
982
- {!exists && (
983
- <i className="bi bi-question-circle ms-1" title="File not found or empty"></i>
984
- )}
985
- </div>
986
- );
987
- };
988
-
989
- const ArtifactTree = ({
990
- treeData,
991
- projectName,
992
- testName,
993
- runtime,
994
- onSelect,
995
- level = 0,
996
- basePath = ''
997
- }: {
998
- treeData: Record<string, any>;
999
- projectName: string;
1000
- testName: string;
1001
- runtime: string;
1002
- onSelect: (path: string) => void;
1003
- level?: number;
1004
- basePath?: string;
1005
- }) => {
1006
- const [expanded, setExpanded] = useState<Record<string, boolean>>({});
1007
-
1008
- const toggleExpand = (path: string) => {
1009
- setExpanded(prev => ({ ...prev, [path]: !prev[path] }));
1010
- };
1011
-
1012
- return (
1013
- <ul className="list-unstyled" style={{ paddingLeft: `${level * 16}px` }}>
1014
- {Object.entries(treeData).map(([name, node]) => {
1015
- const fullPath = basePath ? `${basePath}/${name}` : name;
1016
- const isExpanded = expanded[fullPath];
1017
-
1018
- if (node.__isFile) {
1019
- return (
1020
- <li key={fullPath} className="py-1">
1021
- <a
1022
- href={`reports/${projectName}/${testName
1023
- .split('.')
1024
- .slice(0, -1)
1025
- .join('.')}/${runtime}/${node.path}`}
1026
- target="_blank"
1027
- rel="noopener noreferrer"
1028
- className="text-decoration-none"
1029
- onClick={(e) => {
1030
- e.preventDefault();
1031
- onSelect(node.path);
1032
- }}
1033
- >
1034
- <i className="bi bi-file-earmark-text me-2"></i>
1035
- {name}
1036
- </a>
1037
- </li>
1038
- );
1039
- } else {
1040
- return (
1041
- <li key={fullPath} className="py-1">
1042
- <div className="d-flex align-items-center">
1043
- <button
1044
- className="btn btn-link text-start p-0 text-decoration-none me-1"
1045
- onClick={() => toggleExpand(fullPath)}
1046
- >
1047
- <i
1048
- className={`bi ${isExpanded ? 'bi-folder2-open' : 'bi-folder'} me-2`}
1049
- ></i>
1050
- {name}
1051
- </button>
1052
- </div>
1053
- {isExpanded && (
1054
- <ArtifactTree
1055
- treeData={node}
1056
- projectName={projectName}
1057
- testName={testName}
1058
- runtime={runtime}
1059
- onSelect={onSelect}
1060
- level={level + 1}
1061
- basePath={fullPath}
1062
- />
1063
- )}
1064
- </li>
1065
- );
1066
- }
1067
- })}
1068
- </ul>
1069
- );
1070
- };
1071
-
1072
- const buildArtifactTree = (testData: any) => {
1073
- const artifactPaths = new Set<string>();
1074
- testData.givens?.forEach((given: any) => {
1075
- given.artifacts?.forEach((artifact: string) => artifactPaths.add(artifact));
1076
- given.whens?.forEach((when: any) =>
1077
- when.artifacts?.forEach((artifact: string) => artifactPaths.add(artifact)));
1078
- given.thens?.forEach((then: any) =>
1079
- then.artifacts?.forEach((artifact: string) => artifactPaths.add(artifact)));
1080
- });
1081
-
1082
- const sortedArtifacts = Array.from(artifactPaths).sort();
1083
-
1084
- return sortedArtifacts.reduce((tree, artifactPath) => {
1085
- const parts = artifactPath.split('/');
1086
- let currentLevel = tree;
1087
-
1088
- parts.forEach((part, i) => {
1089
- if (!currentLevel[part]) {
1090
- currentLevel[part] = i === parts.length - 1
1091
- ? { __isFile: true, path: artifactPath }
1092
- : {};
1093
- }
1094
- currentLevel = currentLevel[part];
1095
- });
1096
-
1097
- return tree;
1098
- }, {} as Record<string, any>);
1099
- };
1100
-
1101
- const LogNavItem = ({
1102
- logName,
1103
- logContent,
1104
- activeTab,
1105
- setActiveTab,
1106
- setSelectedFile,
1107
- errorCounts,
1108
- decodedTestPath,
1109
- testsExist,
1110
- }: {
1111
- logName: string;
1112
- logContent: any;
1113
- activeTab: string;
1114
- setActiveTab: (tab: string) => void;
1115
- setSelectedFile: (file: {
1116
- path: string;
1117
- content: string;
1118
- language?: string;
1119
- }) => void;
1120
- errorCounts: {
1121
- runTimeErrors: number;
1122
- typeErrors: number;
1123
- staticErrors: number;
1124
- };
1125
- decodedTestPath: string;
1126
- testsExist: boolean;
1127
- }) => {
1128
- const displayName = logName
1129
- .replace(".json", "")
1130
- .replace(".txt", "")
1131
- .replace(".log", "")
1132
- .replace(/_/g, " ")
1133
- .replace(/^std/, "Standard ")
1134
- .replace(/^exit/, "Exit Code");
1135
-
1136
- const logValue = typeof logContent === "string" ? logContent.trim() : "";
1137
- let statusIndicator: ReactElement<any, any> | null = null;
1138
-
1139
- if (
1140
- logName === STANDARD_LOGS.TYPE_ERRORS &&
1141
- (errorCounts.typeErrors > 0 || (logValue && logValue !== "0"))
1142
- ) {
1143
- statusIndicator = (
1144
- <span className="ms-1">
1145
- ❌ {errorCounts.typeErrors || (logValue ? 1 : 0)}
1146
- </span>
1147
- );
1148
- } else if (
1149
- logName === STANDARD_LOGS.LINT_ERRORS &&
1150
- (errorCounts.staticErrors > 0 || (logValue && logValue !== "0"))
1151
- ) {
1152
- statusIndicator = (
1153
- <span className="ms-1">
1154
- ❌ {errorCounts.staticErrors || (logValue ? 1 : 0)}
1155
- </span>
1156
- );
1157
- } else if (
1158
- logName === RUNTIME_SPECIFIC_LOGS.node.STDERR &&
1159
- (errorCounts.runTimeErrors > 0 || (logValue && logValue !== "0"))
1160
- ) {
1161
- statusIndicator = (
1162
- <span className="ms-1">
1163
- ❌ {errorCounts.runTimeErrors || (logValue ? 1 : 0)}
1164
- </span>
1165
- );
1166
- } else if (logName === STANDARD_LOGS.EXIT && logValue !== "0") {
1167
- statusIndicator = <span className="ms-1">⚠️ {logValue}</span>;
1168
- } else if (logName === STANDARD_LOGS.TESTS && logValue) {
1169
- statusIndicator = (
1170
- <div className="ms-1">
1171
- <TestStatusBadge
1172
- testName={decodedTestPath}
1173
- testsExist={testsExist}
1174
- runTimeErrors={errorCounts.runTimeErrors}
1175
- typeErrors={errorCounts.typeErrors}
1176
- staticErrors={errorCounts.staticErrors}
1177
- variant="compact"
1178
- className="mt-1"
1179
- />
1180
- </div>
1181
- );
1182
- }
1183
-
1184
- return (
1185
- <Nav.Item key={logName}>
1186
- <Nav.Link
1187
- eventKey={logName}
1188
- active={activeTab === logName}
1189
- onClick={() => {
1190
- setActiveTab(logName);
1191
- setSelectedFile({
1192
- path: logName,
1193
- content:
1194
- typeof logContent === "string"
1195
- ? logContent
1196
- : JSON.stringify(logContent, null, 2),
1197
- language: logName.endsWith(".json")
1198
- ? "json"
1199
- : logName.endsWith(".txt")
1200
- ? "plaintext"
1201
- : logName.endsWith(".log")
1202
- ? "log"
1203
- : "plaintext",
1204
- });
1205
- }}
1206
- className="d-flex flex-column align-items-start"
1207
- >
1208
- <div className="d-flex justify-content-between w-100">
1209
- <span className="text-capitalize">{displayName}</span>
1210
- {statusIndicator}
1211
- </div>
1212
- </Nav.Link>
1213
- </Nav.Item>
1214
- );
1215
- };