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