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
|
@@ -0,0 +1,4106 @@
|
|
|
1
|
+
import { createRequire } from 'module';const require = createRequire(import.meta.url);
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __esm = (fn, res) => function __init() {
|
|
5
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
6
|
+
};
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
// src/utils.ts
|
|
13
|
+
import path2 from "path";
|
|
14
|
+
var webEvaluator, tscPather, lintPather, promptPather, getRunnables;
|
|
15
|
+
var init_utils = __esm({
|
|
16
|
+
"src/utils.ts"() {
|
|
17
|
+
"use strict";
|
|
18
|
+
webEvaluator = (d, webArgz) => {
|
|
19
|
+
return `
|
|
20
|
+
import('${d}').then(async (x) => {
|
|
21
|
+
try {
|
|
22
|
+
return await (await x.default).receiveTestResourceConfig(${webArgz})
|
|
23
|
+
} catch (e) {
|
|
24
|
+
console.log("web run failure", e.toString())
|
|
25
|
+
}
|
|
26
|
+
})
|
|
27
|
+
`;
|
|
28
|
+
};
|
|
29
|
+
tscPather = (entryPoint, platform, projectName) => {
|
|
30
|
+
return path2.join(
|
|
31
|
+
"testeranto",
|
|
32
|
+
"reports",
|
|
33
|
+
projectName,
|
|
34
|
+
entryPoint.split(".").slice(0, -1).join("."),
|
|
35
|
+
platform,
|
|
36
|
+
`type_errors.txt`
|
|
37
|
+
);
|
|
38
|
+
};
|
|
39
|
+
lintPather = (entryPoint, platform, projectName) => {
|
|
40
|
+
return path2.join(
|
|
41
|
+
"testeranto",
|
|
42
|
+
"reports",
|
|
43
|
+
projectName,
|
|
44
|
+
entryPoint.split(".").slice(0, -1).join("."),
|
|
45
|
+
platform,
|
|
46
|
+
`lint_errors.txt`
|
|
47
|
+
);
|
|
48
|
+
};
|
|
49
|
+
promptPather = (entryPoint, platform, projectName) => {
|
|
50
|
+
return path2.join(
|
|
51
|
+
"testeranto",
|
|
52
|
+
"reports",
|
|
53
|
+
projectName,
|
|
54
|
+
entryPoint.split(".").slice(0, -1).join("."),
|
|
55
|
+
platform,
|
|
56
|
+
`prompt.txt`
|
|
57
|
+
);
|
|
58
|
+
};
|
|
59
|
+
getRunnables = (tests, projectName, payload = {
|
|
60
|
+
nodeEntryPoints: {},
|
|
61
|
+
nodeEntryPointSidecars: {},
|
|
62
|
+
webEntryPoints: {},
|
|
63
|
+
webEntryPointSidecars: {},
|
|
64
|
+
pureEntryPoints: {},
|
|
65
|
+
pureEntryPointSidecars: {},
|
|
66
|
+
golangEntryPoints: {},
|
|
67
|
+
golangEntryPointSidecars: {},
|
|
68
|
+
pythonEntryPoints: {},
|
|
69
|
+
pythonEntryPointSidecars: {}
|
|
70
|
+
}) => {
|
|
71
|
+
const initializedPayload = {
|
|
72
|
+
nodeEntryPoints: payload.nodeEntryPoints || {},
|
|
73
|
+
nodeEntryPointSidecars: payload.nodeEntryPointSidecars || {},
|
|
74
|
+
webEntryPoints: payload.webEntryPoints || {},
|
|
75
|
+
webEntryPointSidecars: payload.webEntryPointSidecars || {},
|
|
76
|
+
pureEntryPoints: payload.pureEntryPoints || {},
|
|
77
|
+
pureEntryPointSidecars: payload.pureEntryPointSidecars || {},
|
|
78
|
+
golangEntryPoints: payload.golangEntryPoints || {},
|
|
79
|
+
golangEntryPointSidecars: payload.golangEntryPointSidecars || {},
|
|
80
|
+
pythonEntryPoints: payload.pythonEntryPoints || {},
|
|
81
|
+
pythonEntryPointSidecars: payload.pythonEntryPointSidecars || {}
|
|
82
|
+
};
|
|
83
|
+
return tests.reduce((pt, cv, cndx, cry) => {
|
|
84
|
+
if (cv[1] === "node") {
|
|
85
|
+
pt.nodeEntryPoints[cv[0]] = path2.resolve(
|
|
86
|
+
`./testeranto/bundles/node/${projectName}/${cv[0].split(".").slice(0, -1).concat("mjs").join(".")}`
|
|
87
|
+
);
|
|
88
|
+
} else if (cv[1] === "web") {
|
|
89
|
+
pt.webEntryPoints[cv[0]] = path2.resolve(
|
|
90
|
+
`./testeranto/bundles/web/${projectName}/${cv[0].split(".").slice(0, -1).concat("mjs").join(".")}`
|
|
91
|
+
);
|
|
92
|
+
} else if (cv[1] === "pure") {
|
|
93
|
+
pt.pureEntryPoints[cv[0]] = path2.resolve(
|
|
94
|
+
`./testeranto/bundles/pure/${projectName}/${cv[0].split(".").slice(0, -1).concat("mjs").join(".")}`
|
|
95
|
+
);
|
|
96
|
+
} else if (cv[1] === "golang") {
|
|
97
|
+
pt.golangEntryPoints[cv[0]] = path2.resolve(cv[0]);
|
|
98
|
+
} else if (cv[1] === "python") {
|
|
99
|
+
pt.pythonEntryPoints[cv[0]] = path2.resolve(cv[0]);
|
|
100
|
+
}
|
|
101
|
+
cv[3].filter((t) => t[1] === "node").forEach((t) => {
|
|
102
|
+
pt.nodeEntryPointSidecars[`${t[0]}`] = path2.resolve(
|
|
103
|
+
`./testeranto/bundles/node/${projectName}/${cv[0].split(".").slice(0, -1).concat("mjs").join(".")}`
|
|
104
|
+
);
|
|
105
|
+
});
|
|
106
|
+
cv[3].filter((t) => t[1] === "web").forEach((t) => {
|
|
107
|
+
pt.webEntryPointSidecars[`${t[0]}`] = path2.resolve(
|
|
108
|
+
`./testeranto/bundles/web/${projectName}/${cv[0].split(".").slice(0, -1).concat("mjs").join(".")}`
|
|
109
|
+
);
|
|
110
|
+
});
|
|
111
|
+
cv[3].filter((t) => t[1] === "pure").forEach((t) => {
|
|
112
|
+
pt.pureEntryPointSidecars[`${t[0]}`] = path2.resolve(
|
|
113
|
+
`./testeranto/bundles/pure/${projectName}/${cv[0].split(".").slice(0, -1).concat("mjs").join(".")}`
|
|
114
|
+
);
|
|
115
|
+
});
|
|
116
|
+
cv[3].filter((t) => t[1] === "golang").forEach((t) => {
|
|
117
|
+
pt.golangEntryPointSidecars[`${t[0]}`] = path2.resolve(t[0]);
|
|
118
|
+
});
|
|
119
|
+
cv[3].filter((t) => t[1] === "python").forEach((t) => {
|
|
120
|
+
pt.pythonEntryPointSidecars[`${t[0]}`] = path2.resolve(t[0]);
|
|
121
|
+
});
|
|
122
|
+
return pt;
|
|
123
|
+
}, initializedPayload);
|
|
124
|
+
};
|
|
125
|
+
}
|
|
126
|
+
});
|
|
127
|
+
|
|
128
|
+
// src/utils/queue.ts
|
|
129
|
+
var Queue;
|
|
130
|
+
var init_queue = __esm({
|
|
131
|
+
"src/utils/queue.ts"() {
|
|
132
|
+
"use strict";
|
|
133
|
+
Queue = class {
|
|
134
|
+
constructor() {
|
|
135
|
+
this.items = [];
|
|
136
|
+
}
|
|
137
|
+
enqueue(element) {
|
|
138
|
+
this.items.push(element);
|
|
139
|
+
}
|
|
140
|
+
dequeue() {
|
|
141
|
+
if (this.isEmpty()) {
|
|
142
|
+
return "Queue is empty";
|
|
143
|
+
}
|
|
144
|
+
return this.items.shift();
|
|
145
|
+
}
|
|
146
|
+
peek() {
|
|
147
|
+
if (this.isEmpty()) {
|
|
148
|
+
return "Queue is empty";
|
|
149
|
+
}
|
|
150
|
+
return this.items[0];
|
|
151
|
+
}
|
|
152
|
+
isEmpty() {
|
|
153
|
+
return this.items.length === 0;
|
|
154
|
+
}
|
|
155
|
+
size() {
|
|
156
|
+
return this.items.length;
|
|
157
|
+
}
|
|
158
|
+
clear() {
|
|
159
|
+
this.items = [];
|
|
160
|
+
}
|
|
161
|
+
print() {
|
|
162
|
+
console.log(this.items.join(" -> "));
|
|
163
|
+
}
|
|
164
|
+
};
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
|
|
168
|
+
// src/PM/utils.ts
|
|
169
|
+
import ansiC from "ansi-colors";
|
|
170
|
+
import path3 from "path";
|
|
171
|
+
import fs from "fs";
|
|
172
|
+
import crypto from "node:crypto";
|
|
173
|
+
function runtimeLogs(runtime, reportDest) {
|
|
174
|
+
const safeDest = reportDest || `testeranto/reports/default_${Date.now()}`;
|
|
175
|
+
try {
|
|
176
|
+
if (!fs.existsSync(safeDest)) {
|
|
177
|
+
fs.mkdirSync(safeDest, { recursive: true });
|
|
178
|
+
}
|
|
179
|
+
if (runtime === "node") {
|
|
180
|
+
return {
|
|
181
|
+
stdout: fs.createWriteStream(`${safeDest}/stdout.log`),
|
|
182
|
+
stderr: fs.createWriteStream(`${safeDest}/stderr.log`),
|
|
183
|
+
exit: fs.createWriteStream(`${safeDest}/exit.log`)
|
|
184
|
+
};
|
|
185
|
+
} else if (runtime === "web") {
|
|
186
|
+
return {
|
|
187
|
+
info: fs.createWriteStream(`${safeDest}/info.log`),
|
|
188
|
+
warn: fs.createWriteStream(`${safeDest}/warn.log`),
|
|
189
|
+
error: fs.createWriteStream(`${safeDest}/error.log`),
|
|
190
|
+
debug: fs.createWriteStream(`${safeDest}/debug.log`),
|
|
191
|
+
exit: fs.createWriteStream(`${safeDest}/exit.log`)
|
|
192
|
+
};
|
|
193
|
+
} else if (runtime === "pure") {
|
|
194
|
+
return {
|
|
195
|
+
exit: fs.createWriteStream(`${safeDest}/exit.log`)
|
|
196
|
+
};
|
|
197
|
+
} else if (runtime === "pitono") {
|
|
198
|
+
return {
|
|
199
|
+
stdout: fs.createWriteStream(`${safeDest}/stdout.log`),
|
|
200
|
+
stderr: fs.createWriteStream(`${safeDest}/stderr.log`),
|
|
201
|
+
exit: fs.createWriteStream(`${safeDest}/exit.log`)
|
|
202
|
+
};
|
|
203
|
+
} else {
|
|
204
|
+
throw `unknown runtime: ${runtime}`;
|
|
205
|
+
}
|
|
206
|
+
} catch (e) {
|
|
207
|
+
console.error(`Failed to create log streams in ${safeDest}:`, e);
|
|
208
|
+
throw e;
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
function createLogStreams(reportDest, runtime) {
|
|
212
|
+
if (!fs.existsSync(reportDest)) {
|
|
213
|
+
fs.mkdirSync(reportDest, { recursive: true });
|
|
214
|
+
}
|
|
215
|
+
const safeDest = reportDest || `testeranto/reports/default_${Date.now()}`;
|
|
216
|
+
try {
|
|
217
|
+
if (!fs.existsSync(safeDest)) {
|
|
218
|
+
fs.mkdirSync(safeDest, { recursive: true });
|
|
219
|
+
}
|
|
220
|
+
const streams = runtimeLogs(runtime, safeDest);
|
|
221
|
+
return {
|
|
222
|
+
...streams,
|
|
223
|
+
closeAll: () => {
|
|
224
|
+
Object.values(streams).forEach(
|
|
225
|
+
(stream) => !stream.closed && stream.close()
|
|
226
|
+
);
|
|
227
|
+
},
|
|
228
|
+
writeExitCode: (code, error) => {
|
|
229
|
+
if (error) {
|
|
230
|
+
streams.exit.write(`Error: ${error.message}
|
|
231
|
+
`);
|
|
232
|
+
if (error.stack) {
|
|
233
|
+
streams.exit.write(`Stack Trace:
|
|
234
|
+
${error.stack}
|
|
235
|
+
`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
streams.exit.write(`${code}
|
|
239
|
+
`);
|
|
240
|
+
},
|
|
241
|
+
exit: streams.exit
|
|
242
|
+
};
|
|
243
|
+
} catch (e) {
|
|
244
|
+
console.error(`Failed to create log streams in ${safeDest}:`, e);
|
|
245
|
+
throw e;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
async function fileHash(filePath, algorithm = "md5") {
|
|
249
|
+
return new Promise((resolve, reject) => {
|
|
250
|
+
const hash = crypto.createHash(algorithm);
|
|
251
|
+
const fileStream = fs.createReadStream(filePath);
|
|
252
|
+
fileStream.on("data", (data) => {
|
|
253
|
+
hash.update(data);
|
|
254
|
+
});
|
|
255
|
+
fileStream.on("end", () => {
|
|
256
|
+
const fileHash2 = hash.digest("hex");
|
|
257
|
+
resolve(fileHash2);
|
|
258
|
+
});
|
|
259
|
+
fileStream.on("error", (error) => {
|
|
260
|
+
reject(`Error reading file: ${error.message}`);
|
|
261
|
+
});
|
|
262
|
+
});
|
|
263
|
+
}
|
|
264
|
+
async function writeFileAndCreateDir(filePath, data) {
|
|
265
|
+
const dirPath = path3.dirname(filePath);
|
|
266
|
+
try {
|
|
267
|
+
await fs.promises.mkdir(dirPath, { recursive: true });
|
|
268
|
+
await fs.writeFileSync(filePath, data);
|
|
269
|
+
} catch (error) {
|
|
270
|
+
console.error(`Error writing file: ${error}`);
|
|
271
|
+
}
|
|
272
|
+
}
|
|
273
|
+
function isValidUrl(string) {
|
|
274
|
+
try {
|
|
275
|
+
new URL(string);
|
|
276
|
+
return true;
|
|
277
|
+
} catch (err) {
|
|
278
|
+
return false;
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
async function pollForFile(path12, timeout = 2e3) {
|
|
282
|
+
const intervalObj = setInterval(function() {
|
|
283
|
+
const file = path12;
|
|
284
|
+
const fileExists = fs.existsSync(file);
|
|
285
|
+
if (fileExists) {
|
|
286
|
+
clearInterval(intervalObj);
|
|
287
|
+
}
|
|
288
|
+
}, timeout);
|
|
289
|
+
}
|
|
290
|
+
var statusMessagePretty, filesHash, executablePath, puppeteerConfigs;
|
|
291
|
+
var init_utils2 = __esm({
|
|
292
|
+
"src/PM/utils.ts"() {
|
|
293
|
+
"use strict";
|
|
294
|
+
statusMessagePretty = (failures, test, runtime) => {
|
|
295
|
+
if (failures === 0) {
|
|
296
|
+
console.log(ansiC.green(ansiC.inverse(`${runtime} > ${test}`)));
|
|
297
|
+
} else if (failures > 0) {
|
|
298
|
+
console.log(
|
|
299
|
+
ansiC.red(
|
|
300
|
+
ansiC.inverse(
|
|
301
|
+
`${runtime} > ${test} failed ${failures} times (exit code: ${failures})`
|
|
302
|
+
)
|
|
303
|
+
)
|
|
304
|
+
);
|
|
305
|
+
} else {
|
|
306
|
+
console.log(
|
|
307
|
+
ansiC.red(ansiC.inverse(`${runtime} > ${test} crashed (exit code: -1)`))
|
|
308
|
+
);
|
|
309
|
+
}
|
|
310
|
+
};
|
|
311
|
+
filesHash = async (files3, algorithm = "md5") => {
|
|
312
|
+
return new Promise((resolve, reject) => {
|
|
313
|
+
resolve(
|
|
314
|
+
files3.reduce(async (mm, f2) => {
|
|
315
|
+
return await mm + await fileHash(f2);
|
|
316
|
+
}, Promise.resolve(""))
|
|
317
|
+
);
|
|
318
|
+
});
|
|
319
|
+
};
|
|
320
|
+
executablePath = "/opt/homebrew/bin/chromium";
|
|
321
|
+
puppeteerConfigs = {
|
|
322
|
+
slowMo: 1,
|
|
323
|
+
waitForInitialPage: false,
|
|
324
|
+
executablePath,
|
|
325
|
+
headless: true,
|
|
326
|
+
defaultViewport: null,
|
|
327
|
+
// Disable default 800x600 viewport
|
|
328
|
+
dumpio: false,
|
|
329
|
+
devtools: false,
|
|
330
|
+
args: [
|
|
331
|
+
"--allow-file-access-from-files",
|
|
332
|
+
"--allow-insecure-localhost",
|
|
333
|
+
"--allow-running-insecure-content",
|
|
334
|
+
"--auto-open-devtools-for-tabs",
|
|
335
|
+
"--disable-dev-shm-usage",
|
|
336
|
+
"--disable-extensions",
|
|
337
|
+
"--disable-features=site-per-process",
|
|
338
|
+
"--disable-gpu",
|
|
339
|
+
"--disable-setuid-sandbox",
|
|
340
|
+
"--disable-site-isolation-trials",
|
|
341
|
+
"--disable-web-security",
|
|
342
|
+
"--no-first-run",
|
|
343
|
+
"--no-sandbox",
|
|
344
|
+
"--no-startup-window",
|
|
345
|
+
"--reduce-security-for-testing",
|
|
346
|
+
"--remote-allow-origins=*",
|
|
347
|
+
"--start-maximized",
|
|
348
|
+
"--unsafely-treat-insecure-origin-as-secure=*",
|
|
349
|
+
`--remote-debugging-port=3234`
|
|
350
|
+
// "--disable-features=IsolateOrigins,site-per-process",
|
|
351
|
+
// "--disable-features=IsolateOrigins",
|
|
352
|
+
// "--disk-cache-dir=/dev/null",
|
|
353
|
+
// "--disk-cache-size=1",
|
|
354
|
+
// "--no-zygote",
|
|
355
|
+
// "--remote-allow-origins=ws://localhost:3234",
|
|
356
|
+
// "--single-process",
|
|
357
|
+
// "--start-maximized",
|
|
358
|
+
// "--unsafely-treat-insecure-origin-as-secure",
|
|
359
|
+
// "--unsafely-treat-insecure-origin-as-secure=ws://192.168.0.101:3234",
|
|
360
|
+
]
|
|
361
|
+
};
|
|
362
|
+
}
|
|
363
|
+
});
|
|
364
|
+
|
|
365
|
+
// src/esbuildConfigs/index.ts
|
|
366
|
+
var esbuildConfigs_default;
|
|
367
|
+
var init_esbuildConfigs = __esm({
|
|
368
|
+
"src/esbuildConfigs/index.ts"() {
|
|
369
|
+
"use strict";
|
|
370
|
+
esbuildConfigs_default = (config) => {
|
|
371
|
+
return {
|
|
372
|
+
// packages: "external",
|
|
373
|
+
target: "esnext",
|
|
374
|
+
format: "esm",
|
|
375
|
+
splitting: true,
|
|
376
|
+
outExtension: { ".js": ".mjs" },
|
|
377
|
+
outbase: ".",
|
|
378
|
+
jsx: "transform",
|
|
379
|
+
bundle: true,
|
|
380
|
+
minify: config.minify === true,
|
|
381
|
+
write: true,
|
|
382
|
+
loader: {
|
|
383
|
+
".js": "jsx",
|
|
384
|
+
".png": "binary",
|
|
385
|
+
".jpg": "binary"
|
|
386
|
+
}
|
|
387
|
+
};
|
|
388
|
+
};
|
|
389
|
+
}
|
|
390
|
+
});
|
|
391
|
+
|
|
392
|
+
// src/esbuildConfigs/inputFilesPlugin.ts
|
|
393
|
+
import fs2 from "fs";
|
|
394
|
+
var otherInputs, register, inputFilesPlugin_default;
|
|
395
|
+
var init_inputFilesPlugin = __esm({
|
|
396
|
+
"src/esbuildConfigs/inputFilesPlugin.ts"() {
|
|
397
|
+
"use strict";
|
|
398
|
+
otherInputs = {};
|
|
399
|
+
register = (entrypoint, sources) => {
|
|
400
|
+
if (!otherInputs[entrypoint]) {
|
|
401
|
+
otherInputs[entrypoint] = /* @__PURE__ */ new Set();
|
|
402
|
+
}
|
|
403
|
+
sources.forEach((s) => otherInputs[entrypoint].add(s));
|
|
404
|
+
};
|
|
405
|
+
inputFilesPlugin_default = (platform, testName2) => {
|
|
406
|
+
const f2 = `testeranto/metafiles/${platform}/${testName2}.json`;
|
|
407
|
+
if (!fs2.existsSync(`testeranto/metafiles/${platform}`)) {
|
|
408
|
+
fs2.mkdirSync(`testeranto/metafiles/${platform}`, { recursive: true });
|
|
409
|
+
}
|
|
410
|
+
return {
|
|
411
|
+
register,
|
|
412
|
+
inputFilesPluginFactory: {
|
|
413
|
+
name: "metafileWriter",
|
|
414
|
+
setup(build) {
|
|
415
|
+
build.onEnd((result) => {
|
|
416
|
+
fs2.writeFileSync(f2, JSON.stringify(result, null, 2));
|
|
417
|
+
});
|
|
418
|
+
}
|
|
419
|
+
}
|
|
420
|
+
};
|
|
421
|
+
};
|
|
422
|
+
}
|
|
423
|
+
});
|
|
424
|
+
|
|
425
|
+
// src/esbuildConfigs/featuresPlugin.ts
|
|
426
|
+
import path4 from "path";
|
|
427
|
+
var featuresPlugin_default;
|
|
428
|
+
var init_featuresPlugin = __esm({
|
|
429
|
+
"src/esbuildConfigs/featuresPlugin.ts"() {
|
|
430
|
+
"use strict";
|
|
431
|
+
featuresPlugin_default = {
|
|
432
|
+
name: "feature-markdown",
|
|
433
|
+
setup(build) {
|
|
434
|
+
build.onResolve({ filter: /\.md$/ }, (args) => {
|
|
435
|
+
if (args.resolveDir === "")
|
|
436
|
+
return;
|
|
437
|
+
return {
|
|
438
|
+
path: path4.isAbsolute(args.path) ? args.path : path4.join(args.resolveDir, args.path),
|
|
439
|
+
namespace: "feature-markdown"
|
|
440
|
+
};
|
|
441
|
+
});
|
|
442
|
+
build.onLoad(
|
|
443
|
+
{ filter: /.*/, namespace: "feature-markdown" },
|
|
444
|
+
async (args) => {
|
|
445
|
+
return {
|
|
446
|
+
contents: `file://${args.path}`,
|
|
447
|
+
loader: "text"
|
|
448
|
+
// contents: JSON.stringify({ path: args.path }),
|
|
449
|
+
// loader: "json",
|
|
450
|
+
// contents: JSON.stringify({
|
|
451
|
+
// // html: markdownHTML,
|
|
452
|
+
// raw: markdownContent,
|
|
453
|
+
// filename: args.path, //path.basename(args.path),
|
|
454
|
+
// }),
|
|
455
|
+
// loader: "json",
|
|
456
|
+
};
|
|
457
|
+
}
|
|
458
|
+
);
|
|
459
|
+
}
|
|
460
|
+
};
|
|
461
|
+
}
|
|
462
|
+
});
|
|
463
|
+
|
|
464
|
+
// src/esbuildConfigs/rebuildPlugin.ts
|
|
465
|
+
import fs3 from "fs";
|
|
466
|
+
var rebuildPlugin_default;
|
|
467
|
+
var init_rebuildPlugin = __esm({
|
|
468
|
+
"src/esbuildConfigs/rebuildPlugin.ts"() {
|
|
469
|
+
"use strict";
|
|
470
|
+
rebuildPlugin_default = (r) => {
|
|
471
|
+
return {
|
|
472
|
+
name: "rebuild-notify",
|
|
473
|
+
setup: (build) => {
|
|
474
|
+
build.onEnd((result) => {
|
|
475
|
+
console.log(`${r} > build ended with ${result.errors.length} errors`);
|
|
476
|
+
if (result.errors.length > 0) {
|
|
477
|
+
fs3.writeFileSync(
|
|
478
|
+
`./testeranto/reports${r}_build_errors`,
|
|
479
|
+
JSON.stringify(result, null, 2)
|
|
480
|
+
);
|
|
481
|
+
}
|
|
482
|
+
});
|
|
483
|
+
}
|
|
484
|
+
};
|
|
485
|
+
};
|
|
486
|
+
}
|
|
487
|
+
});
|
|
488
|
+
|
|
489
|
+
// src/esbuildConfigs/node.ts
|
|
490
|
+
var node_default;
|
|
491
|
+
var init_node = __esm({
|
|
492
|
+
"src/esbuildConfigs/node.ts"() {
|
|
493
|
+
"use strict";
|
|
494
|
+
init_esbuildConfigs();
|
|
495
|
+
init_inputFilesPlugin();
|
|
496
|
+
init_featuresPlugin();
|
|
497
|
+
init_rebuildPlugin();
|
|
498
|
+
node_default = (config, entryPoints, testName2) => {
|
|
499
|
+
const { inputFilesPluginFactory, register: register2 } = inputFilesPlugin_default(
|
|
500
|
+
"node",
|
|
501
|
+
testName2
|
|
502
|
+
);
|
|
503
|
+
return {
|
|
504
|
+
...esbuildConfigs_default(config),
|
|
505
|
+
splitting: true,
|
|
506
|
+
outdir: `testeranto/bundles/node/${testName2}/`,
|
|
507
|
+
inject: [`./node_modules/testeranto/dist/cjs-shim.js`],
|
|
508
|
+
metafile: true,
|
|
509
|
+
supported: {
|
|
510
|
+
"dynamic-import": true
|
|
511
|
+
},
|
|
512
|
+
define: {
|
|
513
|
+
"process.env.FLUENTFFMPEG_COV": "0"
|
|
514
|
+
},
|
|
515
|
+
absWorkingDir: process.cwd(),
|
|
516
|
+
banner: {
|
|
517
|
+
js: `import { createRequire } from 'module';const require = createRequire(import.meta.url);`
|
|
518
|
+
},
|
|
519
|
+
platform: "node",
|
|
520
|
+
external: ["react", ...config.externals],
|
|
521
|
+
entryPoints: [...entryPoints],
|
|
522
|
+
plugins: [
|
|
523
|
+
featuresPlugin_default,
|
|
524
|
+
inputFilesPluginFactory,
|
|
525
|
+
rebuildPlugin_default("node"),
|
|
526
|
+
...config.nodePlugins.map((p) => p(register2, entryPoints)) || []
|
|
527
|
+
]
|
|
528
|
+
};
|
|
529
|
+
};
|
|
530
|
+
}
|
|
531
|
+
});
|
|
532
|
+
|
|
533
|
+
// src/esbuildConfigs/web.ts
|
|
534
|
+
import { polyfillNode } from "esbuild-plugin-polyfill-node";
|
|
535
|
+
import path5 from "path";
|
|
536
|
+
var web_default;
|
|
537
|
+
var init_web = __esm({
|
|
538
|
+
"src/esbuildConfigs/web.ts"() {
|
|
539
|
+
"use strict";
|
|
540
|
+
init_esbuildConfigs();
|
|
541
|
+
init_inputFilesPlugin();
|
|
542
|
+
init_featuresPlugin();
|
|
543
|
+
init_rebuildPlugin();
|
|
544
|
+
web_default = (config, entryPoints, testName2) => {
|
|
545
|
+
const { inputFilesPluginFactory, register: register2 } = inputFilesPlugin_default(
|
|
546
|
+
"web",
|
|
547
|
+
testName2
|
|
548
|
+
);
|
|
549
|
+
return {
|
|
550
|
+
...esbuildConfigs_default(config),
|
|
551
|
+
treeShaking: true,
|
|
552
|
+
outdir: `testeranto/bundles/web/${testName2}`,
|
|
553
|
+
alias: {
|
|
554
|
+
react: path5.resolve("./node_modules/react")
|
|
555
|
+
},
|
|
556
|
+
metafile: true,
|
|
557
|
+
external: [
|
|
558
|
+
"path",
|
|
559
|
+
"fs",
|
|
560
|
+
"stream",
|
|
561
|
+
"http",
|
|
562
|
+
"constants",
|
|
563
|
+
"net",
|
|
564
|
+
"assert",
|
|
565
|
+
"tls",
|
|
566
|
+
"os",
|
|
567
|
+
"child_process",
|
|
568
|
+
"readline",
|
|
569
|
+
"zlib",
|
|
570
|
+
"crypto",
|
|
571
|
+
"https",
|
|
572
|
+
"util",
|
|
573
|
+
"process",
|
|
574
|
+
"dns"
|
|
575
|
+
],
|
|
576
|
+
platform: "browser",
|
|
577
|
+
entryPoints: [...entryPoints],
|
|
578
|
+
loader: config.webLoaders,
|
|
579
|
+
plugins: [
|
|
580
|
+
featuresPlugin_default,
|
|
581
|
+
inputFilesPluginFactory,
|
|
582
|
+
polyfillNode({
|
|
583
|
+
// You might need to configure specific Node.js modules you want to polyfill
|
|
584
|
+
// Example:
|
|
585
|
+
// modules: {
|
|
586
|
+
// 'util': true,
|
|
587
|
+
// 'fs': false,
|
|
588
|
+
// }
|
|
589
|
+
}),
|
|
590
|
+
rebuildPlugin_default("web"),
|
|
591
|
+
...(config.webPlugins || []).map((p) => p(register2, entryPoints)) || []
|
|
592
|
+
]
|
|
593
|
+
};
|
|
594
|
+
};
|
|
595
|
+
}
|
|
596
|
+
});
|
|
597
|
+
|
|
598
|
+
// src/esbuildConfigs/consoleDetectorPlugin.ts
|
|
599
|
+
import fs4 from "fs";
|
|
600
|
+
var consoleDetectorPlugin;
|
|
601
|
+
var init_consoleDetectorPlugin = __esm({
|
|
602
|
+
"src/esbuildConfigs/consoleDetectorPlugin.ts"() {
|
|
603
|
+
"use strict";
|
|
604
|
+
consoleDetectorPlugin = {
|
|
605
|
+
name: "console-detector",
|
|
606
|
+
setup(build) {
|
|
607
|
+
build.onLoad({ filter: /\.(js|ts)$/ }, async (args) => {
|
|
608
|
+
const contents = await fs4.promises.readFile(args.path, "utf8");
|
|
609
|
+
const consolePattern = /console\.(log|error|warn|info|debug|trace|dir|dirxml|table|group|groupEnd|clear|count|countReset|assert|profile|profileEnd|time|timeLog|timeEnd|timeStamp|context|memory)/g;
|
|
610
|
+
const matches = contents.match(consolePattern);
|
|
611
|
+
if (matches) {
|
|
612
|
+
const uniqueMethods = [...new Set(matches)];
|
|
613
|
+
return {
|
|
614
|
+
warnings: uniqueMethods.map((method) => ({
|
|
615
|
+
text: `call of "${method}" was detected, which is not supported in the pure runtime.`
|
|
616
|
+
// location: {
|
|
617
|
+
// file: args.path,
|
|
618
|
+
// line:
|
|
619
|
+
// contents
|
|
620
|
+
// .split("\n")
|
|
621
|
+
// .findIndex((line) => line.includes(method)) + 1,
|
|
622
|
+
// column: 0,
|
|
623
|
+
// },
|
|
624
|
+
}))
|
|
625
|
+
};
|
|
626
|
+
}
|
|
627
|
+
return null;
|
|
628
|
+
});
|
|
629
|
+
build.onEnd((buildResult) => {
|
|
630
|
+
if (buildResult.warnings.find((br) => br.pluginName === "console-detector"))
|
|
631
|
+
console.warn(
|
|
632
|
+
`Warning: An unsupported method call was detected in a source file used to build for the pure runtime. It is possible that this method call is in a comment block. If you really want to use this function, change this test to the "node" runtime.`
|
|
633
|
+
);
|
|
634
|
+
});
|
|
635
|
+
}
|
|
636
|
+
};
|
|
637
|
+
}
|
|
638
|
+
});
|
|
639
|
+
|
|
640
|
+
// src/esbuildConfigs/pure.ts
|
|
641
|
+
import { isBuiltin } from "node:module";
|
|
642
|
+
var pure_default;
|
|
643
|
+
var init_pure = __esm({
|
|
644
|
+
"src/esbuildConfigs/pure.ts"() {
|
|
645
|
+
"use strict";
|
|
646
|
+
init_esbuildConfigs();
|
|
647
|
+
init_inputFilesPlugin();
|
|
648
|
+
init_featuresPlugin();
|
|
649
|
+
init_consoleDetectorPlugin();
|
|
650
|
+
init_rebuildPlugin();
|
|
651
|
+
pure_default = (config, entryPoints, testName2) => {
|
|
652
|
+
const { inputFilesPluginFactory, register: register2 } = inputFilesPlugin_default(
|
|
653
|
+
"pure",
|
|
654
|
+
testName2
|
|
655
|
+
);
|
|
656
|
+
return {
|
|
657
|
+
...esbuildConfigs_default(config),
|
|
658
|
+
drop: [],
|
|
659
|
+
splitting: true,
|
|
660
|
+
outdir: `testeranto/bundles/pure/${testName2}/`,
|
|
661
|
+
// inject: [`./node_modules/testeranto/dist/cjs-shim.js`],
|
|
662
|
+
metafile: true,
|
|
663
|
+
supported: {
|
|
664
|
+
"dynamic-import": true
|
|
665
|
+
},
|
|
666
|
+
define: {
|
|
667
|
+
"process.env.FLUENTFFMPEG_COV": "0"
|
|
668
|
+
},
|
|
669
|
+
absWorkingDir: process.cwd(),
|
|
670
|
+
banner: {
|
|
671
|
+
js: `import { createRequire } from 'module';const require = createRequire(import.meta.url);`
|
|
672
|
+
},
|
|
673
|
+
platform: "node",
|
|
674
|
+
external: ["react", ...config.externals],
|
|
675
|
+
entryPoints: [...entryPoints],
|
|
676
|
+
plugins: [
|
|
677
|
+
featuresPlugin_default,
|
|
678
|
+
inputFilesPluginFactory,
|
|
679
|
+
consoleDetectorPlugin,
|
|
680
|
+
// nativeImportDetectorPlugin,
|
|
681
|
+
{
|
|
682
|
+
name: "native-node-import-filter",
|
|
683
|
+
setup(build) {
|
|
684
|
+
build.onResolve({ filter: /fs/ }, (args) => {
|
|
685
|
+
if (isBuiltin(args.path)) {
|
|
686
|
+
throw new Error(
|
|
687
|
+
`You attempted to import a node module "${args.path}" into a "pure" test, which is not allowed. If you really want to use this package, convert this test from "pure" to "node"`
|
|
688
|
+
);
|
|
689
|
+
}
|
|
690
|
+
return { path: args.path };
|
|
691
|
+
});
|
|
692
|
+
}
|
|
693
|
+
},
|
|
694
|
+
rebuildPlugin_default("pure"),
|
|
695
|
+
...(config.nodePlugins || []).map((p) => p(register2, entryPoints)) || []
|
|
696
|
+
]
|
|
697
|
+
};
|
|
698
|
+
};
|
|
699
|
+
}
|
|
700
|
+
});
|
|
701
|
+
|
|
702
|
+
// src/PM/base.ts
|
|
703
|
+
import fs5 from "fs";
|
|
704
|
+
import path6 from "path";
|
|
705
|
+
var fileStreams3, fPaths, files, recorders, screenshots, PM_Base;
|
|
706
|
+
var init_base = __esm({
|
|
707
|
+
"src/PM/base.ts"() {
|
|
708
|
+
"use strict";
|
|
709
|
+
fileStreams3 = [];
|
|
710
|
+
fPaths = [];
|
|
711
|
+
files = {};
|
|
712
|
+
recorders = {};
|
|
713
|
+
screenshots = {};
|
|
714
|
+
PM_Base = class {
|
|
715
|
+
constructor(configs) {
|
|
716
|
+
this.configs = configs;
|
|
717
|
+
}
|
|
718
|
+
mapping() {
|
|
719
|
+
return [
|
|
720
|
+
["$", this.$],
|
|
721
|
+
["click", this.click],
|
|
722
|
+
["closePage", this.closePage],
|
|
723
|
+
["createWriteStream", this.createWriteStream],
|
|
724
|
+
["customclose", this.customclose],
|
|
725
|
+
["customScreenShot", this.customScreenShot.bind(this)],
|
|
726
|
+
["end", this.end],
|
|
727
|
+
["existsSync", this.existsSync],
|
|
728
|
+
["focusOn", this.focusOn],
|
|
729
|
+
["getAttribute", this.getAttribute],
|
|
730
|
+
["getInnerHtml", this.getInnerHtml],
|
|
731
|
+
// ["setValue", this.setValue],
|
|
732
|
+
["goto", this.goto.bind(this)],
|
|
733
|
+
["isDisabled", this.isDisabled],
|
|
734
|
+
// ["launchSideCar", this.launchSideCar.bind(this)],
|
|
735
|
+
["mkdirSync", this.mkdirSync],
|
|
736
|
+
["newPage", this.newPage],
|
|
737
|
+
["page", this.page],
|
|
738
|
+
["pages", this.pages],
|
|
739
|
+
["screencast", this.screencast],
|
|
740
|
+
["screencastStop", this.screencastStop],
|
|
741
|
+
// ["stopSideCar", this.stopSideCar.bind(this)],
|
|
742
|
+
["typeInto", this.typeInto],
|
|
743
|
+
["waitForSelector", this.waitForSelector],
|
|
744
|
+
["write", this.write],
|
|
745
|
+
["writeFileSync", this.writeFileSync]
|
|
746
|
+
];
|
|
747
|
+
}
|
|
748
|
+
// keep this forever. do not delete
|
|
749
|
+
// mapping(): [string, (...a) => any][] {
|
|
750
|
+
// return [
|
|
751
|
+
// ["$", (...args) => this.$(...args)],
|
|
752
|
+
// ["click", (...args) => this.click(...args)],
|
|
753
|
+
// ["closePage", (...args) => this.closePage(...args)],
|
|
754
|
+
// ["createWriteStream", (...args) => this.createWriteStream(...args)],
|
|
755
|
+
// ["customclose", (...args) => this.customclose(...args)],
|
|
756
|
+
// ["customScreenShot", (...args) => this.customScreenShot(...args)],
|
|
757
|
+
// ["end", (...args) => this.end(...args)],
|
|
758
|
+
// ["existsSync", (...args) => this.existsSync(...args)],
|
|
759
|
+
// ["focusOn", (...args) => this.focusOn(...args)],
|
|
760
|
+
// ["getAttribute", (...args) => this.getAttribute(...args)],
|
|
761
|
+
// ["getInnerHtml", (...args) => this.getInnerHtml(...args)],
|
|
762
|
+
// // ["setValue", (...args) => this.setValue(...args)],
|
|
763
|
+
// ["goto", (...args) => this.goto(...args)],
|
|
764
|
+
// ["isDisabled", (...args) => this.isDisabled(...args)],
|
|
765
|
+
// // ["launchSideCar", (...args) => this.launchSideCar(...args)],
|
|
766
|
+
// ["mkdirSync", (...args) => this.mkdirSync(...args)],
|
|
767
|
+
// ["newPage", (...args) => this.newPage(...args)],
|
|
768
|
+
// ["page", (...args) => this.page(...args)],
|
|
769
|
+
// ["pages", (...args) => this.pages(...args)],
|
|
770
|
+
// ["screencast", (...args) => this.screencast(...args)],
|
|
771
|
+
// ["screencastStop", (...args) => this.screencastStop(...args)],
|
|
772
|
+
// // ["stopSideCar", (...args) => this.stopSideCar(...args)],
|
|
773
|
+
// ["typeInto", (...args) => this.typeInto(...args)],
|
|
774
|
+
// ["waitForSelector", (...args) => this.waitForSelector(...args)],
|
|
775
|
+
// ["write", (...args) => this.write(...args)],
|
|
776
|
+
// ["writeFileSync", (...args) => this.writeFileSync(...args)],
|
|
777
|
+
// ];
|
|
778
|
+
// }
|
|
779
|
+
// abstract launchSideCar(n: number, testName: string, projectName: string);
|
|
780
|
+
customclose() {
|
|
781
|
+
throw new Error("customclose not implemented.");
|
|
782
|
+
}
|
|
783
|
+
waitForSelector(p, s) {
|
|
784
|
+
return new Promise((res) => {
|
|
785
|
+
this.doInPage(p, async (page) => {
|
|
786
|
+
const x = page.$(s);
|
|
787
|
+
const y = await x;
|
|
788
|
+
res(y !== null);
|
|
789
|
+
});
|
|
790
|
+
});
|
|
791
|
+
}
|
|
792
|
+
closePage(p) {
|
|
793
|
+
return new Promise((res) => {
|
|
794
|
+
this.doInPage(p, async (page) => {
|
|
795
|
+
page.close();
|
|
796
|
+
res({});
|
|
797
|
+
});
|
|
798
|
+
});
|
|
799
|
+
}
|
|
800
|
+
async newPage() {
|
|
801
|
+
return (await this.browser.newPage()).mainFrame()._id;
|
|
802
|
+
}
|
|
803
|
+
goto(p, url3) {
|
|
804
|
+
return new Promise((res) => {
|
|
805
|
+
this.doInPage(p, async (page) => {
|
|
806
|
+
await page?.goto(url3);
|
|
807
|
+
res({});
|
|
808
|
+
});
|
|
809
|
+
});
|
|
810
|
+
}
|
|
811
|
+
$(selector, p) {
|
|
812
|
+
return new Promise((res) => {
|
|
813
|
+
this.doInPage(p, async (page) => {
|
|
814
|
+
const x = await page.$(selector);
|
|
815
|
+
const y = await x?.jsonValue();
|
|
816
|
+
res(y);
|
|
817
|
+
});
|
|
818
|
+
});
|
|
819
|
+
}
|
|
820
|
+
async pages() {
|
|
821
|
+
return (await this.browser.pages()).map((p) => {
|
|
822
|
+
return p.mainFrame()._id;
|
|
823
|
+
});
|
|
824
|
+
}
|
|
825
|
+
async screencast(ssOpts, testName2, page) {
|
|
826
|
+
const p = ssOpts.path;
|
|
827
|
+
const dir = path6.dirname(p);
|
|
828
|
+
fs5.mkdirSync(dir, {
|
|
829
|
+
recursive: true
|
|
830
|
+
});
|
|
831
|
+
if (!files[testName2]) {
|
|
832
|
+
files[testName2] = /* @__PURE__ */ new Set();
|
|
833
|
+
}
|
|
834
|
+
files[testName2].add(ssOpts.path);
|
|
835
|
+
const sPromise = page.screenshot({
|
|
836
|
+
...ssOpts,
|
|
837
|
+
path: p
|
|
838
|
+
});
|
|
839
|
+
if (!screenshots[testName2]) {
|
|
840
|
+
screenshots[testName2] = [];
|
|
841
|
+
}
|
|
842
|
+
screenshots[testName2].push(sPromise);
|
|
843
|
+
await sPromise;
|
|
844
|
+
return sPromise;
|
|
845
|
+
}
|
|
846
|
+
async customScreenShot(ssOpts, testName2, pageUid) {
|
|
847
|
+
const p = ssOpts.path;
|
|
848
|
+
const dir = path6.dirname(p);
|
|
849
|
+
fs5.mkdirSync(dir, {
|
|
850
|
+
recursive: true
|
|
851
|
+
});
|
|
852
|
+
if (!files[testName2]) {
|
|
853
|
+
files[testName2] = /* @__PURE__ */ new Set();
|
|
854
|
+
}
|
|
855
|
+
files[testName2].add(ssOpts.path);
|
|
856
|
+
const page = (await this.browser.pages()).find(
|
|
857
|
+
(p2) => p2.mainFrame()._id === pageUid
|
|
858
|
+
);
|
|
859
|
+
const sPromise = page.screenshot({
|
|
860
|
+
...ssOpts,
|
|
861
|
+
path: p
|
|
862
|
+
});
|
|
863
|
+
if (!screenshots[testName2]) {
|
|
864
|
+
screenshots[testName2] = [];
|
|
865
|
+
}
|
|
866
|
+
screenshots[testName2].push(sPromise);
|
|
867
|
+
await sPromise;
|
|
868
|
+
return sPromise;
|
|
869
|
+
}
|
|
870
|
+
async end(uid) {
|
|
871
|
+
await fileStreams3[uid].end();
|
|
872
|
+
return true;
|
|
873
|
+
}
|
|
874
|
+
existsSync(destFolder) {
|
|
875
|
+
return fs5.existsSync(destFolder);
|
|
876
|
+
}
|
|
877
|
+
async mkdirSync(fp) {
|
|
878
|
+
if (!fs5.existsSync(fp)) {
|
|
879
|
+
return fs5.mkdirSync(fp, {
|
|
880
|
+
recursive: true
|
|
881
|
+
});
|
|
882
|
+
}
|
|
883
|
+
return false;
|
|
884
|
+
}
|
|
885
|
+
async writeFileSync(...x) {
|
|
886
|
+
const filepath = x[0];
|
|
887
|
+
const contents = x[1];
|
|
888
|
+
const testName2 = x[2];
|
|
889
|
+
return new Promise(async (res) => {
|
|
890
|
+
fs5.mkdirSync(path6.dirname(filepath), {
|
|
891
|
+
recursive: true
|
|
892
|
+
});
|
|
893
|
+
if (!files[testName2]) {
|
|
894
|
+
files[testName2] = /* @__PURE__ */ new Set();
|
|
895
|
+
}
|
|
896
|
+
files[testName2].add(filepath);
|
|
897
|
+
await fs5.writeFileSync(filepath, contents);
|
|
898
|
+
res(true);
|
|
899
|
+
});
|
|
900
|
+
}
|
|
901
|
+
async createWriteStream(filepath, testName2) {
|
|
902
|
+
const folder = filepath.split("/").slice(0, -1).join("/");
|
|
903
|
+
return new Promise((res) => {
|
|
904
|
+
if (!fs5.existsSync(folder)) {
|
|
905
|
+
return fs5.mkdirSync(folder, {
|
|
906
|
+
recursive: true
|
|
907
|
+
});
|
|
908
|
+
}
|
|
909
|
+
const f2 = fs5.createWriteStream(filepath);
|
|
910
|
+
fileStreams3.push(f2);
|
|
911
|
+
if (!files[testName2]) {
|
|
912
|
+
files[testName2] = /* @__PURE__ */ new Set();
|
|
913
|
+
}
|
|
914
|
+
files[testName2].add(filepath);
|
|
915
|
+
res(fileStreams3.length - 1);
|
|
916
|
+
});
|
|
917
|
+
}
|
|
918
|
+
testArtiFactoryfileWriter(tLog, callback) {
|
|
919
|
+
return (fPath, value) => {
|
|
920
|
+
callback(
|
|
921
|
+
new Promise((res, rej) => {
|
|
922
|
+
tLog("testArtiFactory =>", fPath);
|
|
923
|
+
const cleanPath = path6.resolve(fPath);
|
|
924
|
+
fPaths.push(cleanPath.replace(process.cwd(), ``));
|
|
925
|
+
const targetDir = cleanPath.split("/").slice(0, -1).join("/");
|
|
926
|
+
fs5.mkdir(targetDir, { recursive: true }, async (error) => {
|
|
927
|
+
if (error) {
|
|
928
|
+
console.error(`\u2757\uFE0FtestArtiFactory failed`, targetDir, error);
|
|
929
|
+
}
|
|
930
|
+
fs5.writeFileSync(
|
|
931
|
+
path6.resolve(
|
|
932
|
+
targetDir.split("/").slice(0, -1).join("/"),
|
|
933
|
+
"manifest"
|
|
934
|
+
),
|
|
935
|
+
fPaths.join(`
|
|
936
|
+
`),
|
|
937
|
+
{
|
|
938
|
+
encoding: "utf-8"
|
|
939
|
+
}
|
|
940
|
+
);
|
|
941
|
+
if (Buffer.isBuffer(value)) {
|
|
942
|
+
fs5.writeFileSync(fPath, value, "binary");
|
|
943
|
+
res();
|
|
944
|
+
} else if (`string` === typeof value) {
|
|
945
|
+
fs5.writeFileSync(fPath, value.toString(), {
|
|
946
|
+
encoding: "utf-8"
|
|
947
|
+
});
|
|
948
|
+
res();
|
|
949
|
+
} else {
|
|
950
|
+
const pipeStream = value;
|
|
951
|
+
const myFile = fs5.createWriteStream(fPath);
|
|
952
|
+
pipeStream.pipe(myFile);
|
|
953
|
+
pipeStream.on("close", () => {
|
|
954
|
+
myFile.close();
|
|
955
|
+
res();
|
|
956
|
+
});
|
|
957
|
+
}
|
|
958
|
+
});
|
|
959
|
+
})
|
|
960
|
+
);
|
|
961
|
+
};
|
|
962
|
+
}
|
|
963
|
+
async write(uid, contents) {
|
|
964
|
+
return new Promise((res) => {
|
|
965
|
+
const x = fileStreams3[uid].write(contents);
|
|
966
|
+
res(x);
|
|
967
|
+
});
|
|
968
|
+
}
|
|
969
|
+
page(p) {
|
|
970
|
+
return p;
|
|
971
|
+
}
|
|
972
|
+
click(selector, page) {
|
|
973
|
+
return page.click(selector);
|
|
974
|
+
}
|
|
975
|
+
async focusOn(selector, p) {
|
|
976
|
+
this.doInPage(p, (page) => {
|
|
977
|
+
return page.focus(selector);
|
|
978
|
+
});
|
|
979
|
+
}
|
|
980
|
+
async typeInto(value, p) {
|
|
981
|
+
this.doInPage(p, (page) => {
|
|
982
|
+
return page.keyboard.type(value);
|
|
983
|
+
});
|
|
984
|
+
}
|
|
985
|
+
// setValue(value: string, p: string) {
|
|
986
|
+
// this.doInPage(p, (page) => {
|
|
987
|
+
// return page.keyboard.type(value);
|
|
988
|
+
// });
|
|
989
|
+
// }
|
|
990
|
+
getAttribute(selector, attribute, p) {
|
|
991
|
+
this.doInPage(p, (page) => {
|
|
992
|
+
return page.$eval(selector, (input) => input.getAttribute(attribute));
|
|
993
|
+
});
|
|
994
|
+
}
|
|
995
|
+
async getInnerHtml(selector, p) {
|
|
996
|
+
return new Promise((res, rej) => {
|
|
997
|
+
this.doInPage(p, async (page) => {
|
|
998
|
+
const e = await page.$(selector);
|
|
999
|
+
if (!e) {
|
|
1000
|
+
rej();
|
|
1001
|
+
} else {
|
|
1002
|
+
const text = await (await e.getProperty("textContent")).jsonValue();
|
|
1003
|
+
res(text);
|
|
1004
|
+
}
|
|
1005
|
+
});
|
|
1006
|
+
});
|
|
1007
|
+
}
|
|
1008
|
+
isDisabled(selector, p) {
|
|
1009
|
+
this.doInPage(p, async (page) => {
|
|
1010
|
+
return await page.$eval(selector, (input) => {
|
|
1011
|
+
return input.disabled;
|
|
1012
|
+
});
|
|
1013
|
+
});
|
|
1014
|
+
}
|
|
1015
|
+
screencastStop(s) {
|
|
1016
|
+
return recorders[s].stop();
|
|
1017
|
+
}
|
|
1018
|
+
async doInPage(p, cb) {
|
|
1019
|
+
(await this.browser.pages()).forEach((page) => {
|
|
1020
|
+
const frame = page.mainFrame();
|
|
1021
|
+
if (frame._id === p) {
|
|
1022
|
+
return cb(page);
|
|
1023
|
+
}
|
|
1024
|
+
});
|
|
1025
|
+
}
|
|
1026
|
+
};
|
|
1027
|
+
}
|
|
1028
|
+
});
|
|
1029
|
+
|
|
1030
|
+
// src/PM/PM_WithWebSocket.ts
|
|
1031
|
+
import { spawn } from "node:child_process";
|
|
1032
|
+
import fs6 from "fs";
|
|
1033
|
+
import http from "http";
|
|
1034
|
+
import url from "url";
|
|
1035
|
+
import mime from "mime-types";
|
|
1036
|
+
import { WebSocketServer } from "ws";
|
|
1037
|
+
var PM_WithWebSocket;
|
|
1038
|
+
var init_PM_WithWebSocket = __esm({
|
|
1039
|
+
"src/PM/PM_WithWebSocket.ts"() {
|
|
1040
|
+
"use strict";
|
|
1041
|
+
init_base();
|
|
1042
|
+
PM_WithWebSocket = class extends PM_Base {
|
|
1043
|
+
constructor(configs) {
|
|
1044
|
+
super(configs);
|
|
1045
|
+
this.clients = /* @__PURE__ */ new Set();
|
|
1046
|
+
this.runningProcesses = /* @__PURE__ */ new Map();
|
|
1047
|
+
this.allProcesses = /* @__PURE__ */ new Map();
|
|
1048
|
+
this.processLogs = /* @__PURE__ */ new Map();
|
|
1049
|
+
this.httpServer = http.createServer(this.requestHandler.bind(this));
|
|
1050
|
+
this.wss = new WebSocketServer({ server: this.httpServer });
|
|
1051
|
+
this.wss.on("connection", (ws) => {
|
|
1052
|
+
this.clients.add(ws);
|
|
1053
|
+
console.log("Client connected");
|
|
1054
|
+
ws.on("message", (data) => {
|
|
1055
|
+
try {
|
|
1056
|
+
const message = JSON.parse(data.toString());
|
|
1057
|
+
if (message.type === "executeCommand") {
|
|
1058
|
+
const executeMessage = message;
|
|
1059
|
+
if (message.command && message.command.trim().startsWith("aider")) {
|
|
1060
|
+
console.log(`Executing command: ${message.command}`);
|
|
1061
|
+
const processId = Date.now().toString();
|
|
1062
|
+
const child = spawn(message.command, {
|
|
1063
|
+
shell: true,
|
|
1064
|
+
cwd: process.cwd()
|
|
1065
|
+
});
|
|
1066
|
+
this.runningProcesses.set(processId, child);
|
|
1067
|
+
this.allProcesses.set(processId, {
|
|
1068
|
+
child,
|
|
1069
|
+
status: "running",
|
|
1070
|
+
command: message.command,
|
|
1071
|
+
pid: child.pid,
|
|
1072
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1073
|
+
type: "process",
|
|
1074
|
+
category: "aider"
|
|
1075
|
+
});
|
|
1076
|
+
this.processLogs.set(processId, []);
|
|
1077
|
+
this.broadcast({
|
|
1078
|
+
type: "processStarted",
|
|
1079
|
+
processId,
|
|
1080
|
+
command: message.command,
|
|
1081
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1082
|
+
logs: []
|
|
1083
|
+
});
|
|
1084
|
+
child.stdout?.on("data", (data2) => {
|
|
1085
|
+
const logData = data2.toString();
|
|
1086
|
+
const logs = this.processLogs.get(processId) || [];
|
|
1087
|
+
logs.push(logData);
|
|
1088
|
+
this.processLogs.set(processId, logs);
|
|
1089
|
+
this.broadcast({
|
|
1090
|
+
type: "processStdout",
|
|
1091
|
+
processId,
|
|
1092
|
+
data: logData,
|
|
1093
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1094
|
+
});
|
|
1095
|
+
});
|
|
1096
|
+
child.stderr?.on("data", (data2) => {
|
|
1097
|
+
const logData = data2.toString();
|
|
1098
|
+
const logs = this.processLogs.get(processId) || [];
|
|
1099
|
+
logs.push(logData);
|
|
1100
|
+
this.processLogs.set(processId, logs);
|
|
1101
|
+
this.broadcast({
|
|
1102
|
+
type: "processStderr",
|
|
1103
|
+
processId,
|
|
1104
|
+
data: logData,
|
|
1105
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1106
|
+
});
|
|
1107
|
+
});
|
|
1108
|
+
child.on("error", (error) => {
|
|
1109
|
+
console.error(`Failed to execute command: ${error}`);
|
|
1110
|
+
this.runningProcesses.delete(processId);
|
|
1111
|
+
const processInfo = this.allProcesses.get(processId);
|
|
1112
|
+
if (processInfo) {
|
|
1113
|
+
this.allProcesses.set(processId, {
|
|
1114
|
+
...processInfo,
|
|
1115
|
+
status: "error",
|
|
1116
|
+
error: error.message
|
|
1117
|
+
});
|
|
1118
|
+
}
|
|
1119
|
+
this.broadcast({
|
|
1120
|
+
type: "processError",
|
|
1121
|
+
processId,
|
|
1122
|
+
error: error.message,
|
|
1123
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1124
|
+
});
|
|
1125
|
+
});
|
|
1126
|
+
child.on("exit", (code) => {
|
|
1127
|
+
console.log(`Command exited with code ${code}`);
|
|
1128
|
+
this.runningProcesses.delete(processId);
|
|
1129
|
+
const processInfo = this.allProcesses.get(processId);
|
|
1130
|
+
if (processInfo) {
|
|
1131
|
+
this.allProcesses.set(processId, {
|
|
1132
|
+
...processInfo,
|
|
1133
|
+
status: "exited",
|
|
1134
|
+
exitCode: code
|
|
1135
|
+
});
|
|
1136
|
+
}
|
|
1137
|
+
this.broadcast({
|
|
1138
|
+
type: "processExited",
|
|
1139
|
+
processId,
|
|
1140
|
+
exitCode: code,
|
|
1141
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString()
|
|
1142
|
+
});
|
|
1143
|
+
});
|
|
1144
|
+
} else {
|
|
1145
|
+
console.error('Invalid command: must start with "aider"');
|
|
1146
|
+
}
|
|
1147
|
+
} else if (message.type === "getRunningProcesses") {
|
|
1148
|
+
const getRunningMessage = message;
|
|
1149
|
+
const processes = Array.from(this.allProcesses.entries()).map(
|
|
1150
|
+
([id, procInfo]) => ({
|
|
1151
|
+
processId: id,
|
|
1152
|
+
command: procInfo.command,
|
|
1153
|
+
pid: procInfo.pid,
|
|
1154
|
+
status: procInfo.status,
|
|
1155
|
+
exitCode: procInfo.exitCode,
|
|
1156
|
+
error: procInfo.error,
|
|
1157
|
+
timestamp: procInfo.timestamp,
|
|
1158
|
+
category: procInfo.category,
|
|
1159
|
+
testName: procInfo.testName,
|
|
1160
|
+
platform: procInfo.platform,
|
|
1161
|
+
logs: this.processLogs.get(id) || []
|
|
1162
|
+
})
|
|
1163
|
+
);
|
|
1164
|
+
ws.send(
|
|
1165
|
+
JSON.stringify({
|
|
1166
|
+
type: "runningProcesses",
|
|
1167
|
+
processes
|
|
1168
|
+
})
|
|
1169
|
+
);
|
|
1170
|
+
} else if (message.type === "getProcess") {
|
|
1171
|
+
const getProcessMessage = message;
|
|
1172
|
+
const processId = message.processId;
|
|
1173
|
+
const procInfo = this.allProcesses.get(processId);
|
|
1174
|
+
if (procInfo) {
|
|
1175
|
+
ws.send(
|
|
1176
|
+
JSON.stringify({
|
|
1177
|
+
type: "processData",
|
|
1178
|
+
processId,
|
|
1179
|
+
command: procInfo.command,
|
|
1180
|
+
pid: procInfo.pid,
|
|
1181
|
+
status: procInfo.status,
|
|
1182
|
+
exitCode: procInfo.exitCode,
|
|
1183
|
+
error: procInfo.error,
|
|
1184
|
+
timestamp: procInfo.timestamp,
|
|
1185
|
+
category: procInfo.category,
|
|
1186
|
+
testName: procInfo.testName,
|
|
1187
|
+
platform: procInfo.platform,
|
|
1188
|
+
logs: this.processLogs.get(processId) || []
|
|
1189
|
+
})
|
|
1190
|
+
);
|
|
1191
|
+
}
|
|
1192
|
+
} else if (message.type === "stdin") {
|
|
1193
|
+
const stdinMessage = message;
|
|
1194
|
+
const processId = message.processId;
|
|
1195
|
+
const data2 = message.data;
|
|
1196
|
+
console.log("Received stdin for process", processId, ":", data2);
|
|
1197
|
+
const childProcess = this.runningProcesses.get(processId);
|
|
1198
|
+
if (childProcess && childProcess.stdin) {
|
|
1199
|
+
console.log("Writing to process stdin");
|
|
1200
|
+
childProcess.stdin.write(data2);
|
|
1201
|
+
} else {
|
|
1202
|
+
console.log(
|
|
1203
|
+
"Cannot write to stdin - process not found or no stdin:",
|
|
1204
|
+
{
|
|
1205
|
+
processExists: !!childProcess,
|
|
1206
|
+
stdinExists: childProcess?.stdin ? true : false
|
|
1207
|
+
}
|
|
1208
|
+
);
|
|
1209
|
+
}
|
|
1210
|
+
} else if (message.type === "killProcess") {
|
|
1211
|
+
const killProcessMessage = message;
|
|
1212
|
+
const processId = message.processId;
|
|
1213
|
+
console.log("Received killProcess for process", processId);
|
|
1214
|
+
const childProcess = this.runningProcesses.get(processId);
|
|
1215
|
+
if (childProcess) {
|
|
1216
|
+
console.log("Killing process");
|
|
1217
|
+
childProcess.kill("SIGTERM");
|
|
1218
|
+
} else {
|
|
1219
|
+
console.log("Cannot kill process - process not found:", {
|
|
1220
|
+
processExists: !!childProcess
|
|
1221
|
+
});
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
} catch (error) {
|
|
1225
|
+
console.error("Error handling WebSocket message:", error);
|
|
1226
|
+
}
|
|
1227
|
+
});
|
|
1228
|
+
ws.on("close", () => {
|
|
1229
|
+
this.clients.delete(ws);
|
|
1230
|
+
console.log("Client disconnected");
|
|
1231
|
+
});
|
|
1232
|
+
ws.on("error", (error) => {
|
|
1233
|
+
console.error("WebSocket error:", error);
|
|
1234
|
+
this.clients.delete(ws);
|
|
1235
|
+
});
|
|
1236
|
+
});
|
|
1237
|
+
const httpPort = Number(process.env.HTTP_PORT) || 3e3;
|
|
1238
|
+
this.httpServer.listen(httpPort, () => {
|
|
1239
|
+
console.log(`HTTP server running on http://localhost:${httpPort}`);
|
|
1240
|
+
});
|
|
1241
|
+
}
|
|
1242
|
+
requestHandler(req, res) {
|
|
1243
|
+
const parsedUrl = url.parse(req.url || "/");
|
|
1244
|
+
const pathname = parsedUrl.pathname || "/";
|
|
1245
|
+
if (pathname === "/health") {
|
|
1246
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
1247
|
+
res.end(
|
|
1248
|
+
JSON.stringify({ status: "ok", timestamp: (/* @__PURE__ */ new Date()).toISOString() })
|
|
1249
|
+
);
|
|
1250
|
+
return;
|
|
1251
|
+
}
|
|
1252
|
+
let processedPathname = pathname;
|
|
1253
|
+
if (processedPathname === "/") {
|
|
1254
|
+
processedPathname = "/index.html";
|
|
1255
|
+
}
|
|
1256
|
+
let filePath = processedPathname.substring(1);
|
|
1257
|
+
if (filePath.startsWith("reports/")) {
|
|
1258
|
+
filePath = `testeranto/${filePath}`;
|
|
1259
|
+
} else if (filePath.startsWith("metafiles/")) {
|
|
1260
|
+
filePath = `testeranto/${filePath}`;
|
|
1261
|
+
} else if (filePath === "projects.json") {
|
|
1262
|
+
filePath = `testeranto/${filePath}`;
|
|
1263
|
+
} else {
|
|
1264
|
+
const possiblePaths = [
|
|
1265
|
+
`dist/${filePath}`,
|
|
1266
|
+
`testeranto/dist/${filePath}`,
|
|
1267
|
+
`../dist/${filePath}`,
|
|
1268
|
+
`./${filePath}`
|
|
1269
|
+
];
|
|
1270
|
+
let foundPath = null;
|
|
1271
|
+
for (const possiblePath of possiblePaths) {
|
|
1272
|
+
if (fs6.existsSync(possiblePath)) {
|
|
1273
|
+
foundPath = possiblePath;
|
|
1274
|
+
break;
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1277
|
+
if (foundPath) {
|
|
1278
|
+
filePath = foundPath;
|
|
1279
|
+
} else {
|
|
1280
|
+
const indexPath = this.findIndexHtml();
|
|
1281
|
+
if (indexPath) {
|
|
1282
|
+
fs6.readFile(indexPath, (err, data) => {
|
|
1283
|
+
if (err) {
|
|
1284
|
+
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
1285
|
+
res.end("404 Not Found");
|
|
1286
|
+
return;
|
|
1287
|
+
}
|
|
1288
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
1289
|
+
res.end(data);
|
|
1290
|
+
});
|
|
1291
|
+
return;
|
|
1292
|
+
} else {
|
|
1293
|
+
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
1294
|
+
res.end("404 Not Found");
|
|
1295
|
+
return;
|
|
1296
|
+
}
|
|
1297
|
+
}
|
|
1298
|
+
}
|
|
1299
|
+
fs6.exists(filePath, (exists) => {
|
|
1300
|
+
if (!exists) {
|
|
1301
|
+
if (!processedPathname.includes(".") && processedPathname !== "/") {
|
|
1302
|
+
const indexPath = this.findIndexHtml();
|
|
1303
|
+
if (indexPath) {
|
|
1304
|
+
fs6.readFile(indexPath, (err, data) => {
|
|
1305
|
+
if (err) {
|
|
1306
|
+
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
1307
|
+
res.end("404 Not Found");
|
|
1308
|
+
return;
|
|
1309
|
+
}
|
|
1310
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
1311
|
+
res.end(data);
|
|
1312
|
+
});
|
|
1313
|
+
return;
|
|
1314
|
+
} else {
|
|
1315
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
1316
|
+
res.end(`
|
|
1317
|
+
<html>
|
|
1318
|
+
<body>
|
|
1319
|
+
<h1>Testeranto is running</h1>
|
|
1320
|
+
<p>Frontend files are not built yet. Run 'npm run build' to build the frontend.</p>
|
|
1321
|
+
</body>
|
|
1322
|
+
</html>
|
|
1323
|
+
`);
|
|
1324
|
+
return;
|
|
1325
|
+
}
|
|
1326
|
+
}
|
|
1327
|
+
res.writeHead(404, { "Content-Type": "text/plain" });
|
|
1328
|
+
res.end("404 Not Found");
|
|
1329
|
+
return;
|
|
1330
|
+
}
|
|
1331
|
+
fs6.readFile(filePath, (err, data) => {
|
|
1332
|
+
if (err) {
|
|
1333
|
+
res.writeHead(500, { "Content-Type": "text/plain" });
|
|
1334
|
+
res.end("500 Internal Server Error");
|
|
1335
|
+
return;
|
|
1336
|
+
}
|
|
1337
|
+
if (filePath.endsWith(".html")) {
|
|
1338
|
+
let content = data.toString();
|
|
1339
|
+
if (content.includes("</body>")) {
|
|
1340
|
+
const configScript = `
|
|
1341
|
+
<script>
|
|
1342
|
+
window.testerantoConfig = ${JSON.stringify({
|
|
1343
|
+
githubOAuth: {
|
|
1344
|
+
clientId: process.env.GITHUB_CLIENT_ID || ""
|
|
1345
|
+
},
|
|
1346
|
+
serverOrigin: process.env.SERVER_ORIGIN || "http://localhost:3000"
|
|
1347
|
+
})};
|
|
1348
|
+
</script>
|
|
1349
|
+
`;
|
|
1350
|
+
content = content.replace("</body>", `${configScript}</body>`);
|
|
1351
|
+
}
|
|
1352
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
1353
|
+
res.end(content);
|
|
1354
|
+
} else {
|
|
1355
|
+
const mimeType = mime.lookup(filePath) || "application/octet-stream";
|
|
1356
|
+
res.writeHead(200, { "Content-Type": mimeType });
|
|
1357
|
+
res.end(data);
|
|
1358
|
+
}
|
|
1359
|
+
});
|
|
1360
|
+
});
|
|
1361
|
+
}
|
|
1362
|
+
findIndexHtml() {
|
|
1363
|
+
const possiblePaths = [
|
|
1364
|
+
"dist/index.html",
|
|
1365
|
+
"testeranto/dist/index.html",
|
|
1366
|
+
"../dist/index.html",
|
|
1367
|
+
"./index.html"
|
|
1368
|
+
];
|
|
1369
|
+
for (const path12 of possiblePaths) {
|
|
1370
|
+
if (fs6.existsSync(path12)) {
|
|
1371
|
+
return path12;
|
|
1372
|
+
}
|
|
1373
|
+
}
|
|
1374
|
+
return null;
|
|
1375
|
+
}
|
|
1376
|
+
// Add a method to track promise-based processes
|
|
1377
|
+
addPromiseProcess(processId, promise, command, category = "other", testName2, platform, onResolve, onReject) {
|
|
1378
|
+
this.runningProcesses.set(processId, promise);
|
|
1379
|
+
this.allProcesses.set(processId, {
|
|
1380
|
+
promise,
|
|
1381
|
+
status: "running",
|
|
1382
|
+
command,
|
|
1383
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1384
|
+
type: "promise",
|
|
1385
|
+
category,
|
|
1386
|
+
testName: testName2,
|
|
1387
|
+
platform
|
|
1388
|
+
});
|
|
1389
|
+
this.processLogs.set(processId, []);
|
|
1390
|
+
const startMessage = `Starting: ${command}`;
|
|
1391
|
+
const logs = this.processLogs.get(processId) || [];
|
|
1392
|
+
logs.push(startMessage);
|
|
1393
|
+
this.processLogs.set(processId, logs);
|
|
1394
|
+
this.broadcast({
|
|
1395
|
+
type: "processStarted",
|
|
1396
|
+
processId,
|
|
1397
|
+
command,
|
|
1398
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1399
|
+
logs: [startMessage]
|
|
1400
|
+
});
|
|
1401
|
+
promise.then((result) => {
|
|
1402
|
+
this.runningProcesses.delete(processId);
|
|
1403
|
+
const processInfo = this.allProcesses.get(processId);
|
|
1404
|
+
if (processInfo) {
|
|
1405
|
+
this.allProcesses.set(processId, {
|
|
1406
|
+
...processInfo,
|
|
1407
|
+
status: "completed",
|
|
1408
|
+
exitCode: 0
|
|
1409
|
+
});
|
|
1410
|
+
}
|
|
1411
|
+
const successMessage = `Completed successfully with result: ${JSON.stringify(
|
|
1412
|
+
result
|
|
1413
|
+
)}`;
|
|
1414
|
+
const currentLogs = this.processLogs.get(processId) || [];
|
|
1415
|
+
currentLogs.push(successMessage);
|
|
1416
|
+
this.processLogs.set(processId, currentLogs);
|
|
1417
|
+
this.broadcast({
|
|
1418
|
+
type: "processExited",
|
|
1419
|
+
processId,
|
|
1420
|
+
exitCode: 0,
|
|
1421
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1422
|
+
logs: [successMessage]
|
|
1423
|
+
});
|
|
1424
|
+
if (onResolve)
|
|
1425
|
+
onResolve(result);
|
|
1426
|
+
}).catch((error) => {
|
|
1427
|
+
this.runningProcesses.delete(processId);
|
|
1428
|
+
const processInfo = this.allProcesses.get(processId);
|
|
1429
|
+
if (processInfo) {
|
|
1430
|
+
this.allProcesses.set(processId, {
|
|
1431
|
+
...processInfo,
|
|
1432
|
+
status: "error",
|
|
1433
|
+
error: error.message
|
|
1434
|
+
});
|
|
1435
|
+
}
|
|
1436
|
+
const errorMessage = `Failed with error: ${error.message}`;
|
|
1437
|
+
const currentLogs = this.processLogs.get(processId) || [];
|
|
1438
|
+
currentLogs.push(errorMessage);
|
|
1439
|
+
this.processLogs.set(processId, currentLogs);
|
|
1440
|
+
this.broadcast({
|
|
1441
|
+
type: "processError",
|
|
1442
|
+
processId,
|
|
1443
|
+
error: error.message,
|
|
1444
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1445
|
+
logs: [errorMessage]
|
|
1446
|
+
});
|
|
1447
|
+
if (onReject)
|
|
1448
|
+
onReject(error);
|
|
1449
|
+
});
|
|
1450
|
+
return processId;
|
|
1451
|
+
}
|
|
1452
|
+
broadcast(message) {
|
|
1453
|
+
const data = typeof message === "string" ? message : JSON.stringify(message);
|
|
1454
|
+
this.clients.forEach((client) => {
|
|
1455
|
+
if (client.readyState === 1) {
|
|
1456
|
+
client.send(data);
|
|
1457
|
+
}
|
|
1458
|
+
});
|
|
1459
|
+
}
|
|
1460
|
+
// Helper methods to get processes by category
|
|
1461
|
+
getProcessesByCategory(category) {
|
|
1462
|
+
return Array.from(this.allProcesses.entries()).filter(([id, procInfo]) => procInfo.category === category).map(([id, procInfo]) => ({
|
|
1463
|
+
processId: id,
|
|
1464
|
+
command: procInfo.command,
|
|
1465
|
+
pid: procInfo.pid,
|
|
1466
|
+
status: procInfo.status,
|
|
1467
|
+
exitCode: procInfo.exitCode,
|
|
1468
|
+
error: procInfo.error,
|
|
1469
|
+
timestamp: procInfo.timestamp,
|
|
1470
|
+
category: procInfo.category,
|
|
1471
|
+
testName: procInfo.testName,
|
|
1472
|
+
platform: procInfo.platform,
|
|
1473
|
+
logs: this.processLogs.get(id) || []
|
|
1474
|
+
}));
|
|
1475
|
+
}
|
|
1476
|
+
getBDDTestProcesses() {
|
|
1477
|
+
return this.getProcessesByCategory("bdd-test");
|
|
1478
|
+
}
|
|
1479
|
+
getBuildTimeProcesses() {
|
|
1480
|
+
return this.getProcessesByCategory("build-time");
|
|
1481
|
+
}
|
|
1482
|
+
getAiderProcesses() {
|
|
1483
|
+
return this.getProcessesByCategory("aider");
|
|
1484
|
+
}
|
|
1485
|
+
getProcessesByTestName(testName2) {
|
|
1486
|
+
return Array.from(this.allProcesses.entries()).filter(([id, procInfo]) => procInfo.testName === testName2).map(([id, procInfo]) => ({
|
|
1487
|
+
processId: id,
|
|
1488
|
+
command: procInfo.command,
|
|
1489
|
+
pid: procInfo.pid,
|
|
1490
|
+
status: procInfo.status,
|
|
1491
|
+
exitCode: procInfo.exitCode,
|
|
1492
|
+
error: procInfo.error,
|
|
1493
|
+
timestamp: procInfo.timestamp,
|
|
1494
|
+
category: procInfo.category,
|
|
1495
|
+
testName: procInfo.testName,
|
|
1496
|
+
platform: procInfo.platform,
|
|
1497
|
+
logs: this.processLogs.get(id) || []
|
|
1498
|
+
}));
|
|
1499
|
+
}
|
|
1500
|
+
getProcessesByPlatform(platform) {
|
|
1501
|
+
return Array.from(this.allProcesses.entries()).filter(([id, procInfo]) => procInfo.platform === platform).map(([id, procInfo]) => ({
|
|
1502
|
+
processId: id,
|
|
1503
|
+
command: procInfo.command,
|
|
1504
|
+
pid: procInfo.pid,
|
|
1505
|
+
status: procInfo.status,
|
|
1506
|
+
exitCode: procInfo.exitCode,
|
|
1507
|
+
error: procInfo.error,
|
|
1508
|
+
timestamp: procInfo.timestamp,
|
|
1509
|
+
category: procInfo.category,
|
|
1510
|
+
testName: procInfo.testName,
|
|
1511
|
+
platform: procInfo.platform,
|
|
1512
|
+
logs: this.processLogs.get(id) || []
|
|
1513
|
+
}));
|
|
1514
|
+
}
|
|
1515
|
+
};
|
|
1516
|
+
}
|
|
1517
|
+
});
|
|
1518
|
+
|
|
1519
|
+
// src/PM/PM_WithBuild.ts
|
|
1520
|
+
import esbuild from "esbuild";
|
|
1521
|
+
var PM_WithBuild;
|
|
1522
|
+
var init_PM_WithBuild = __esm({
|
|
1523
|
+
"src/PM/PM_WithBuild.ts"() {
|
|
1524
|
+
"use strict";
|
|
1525
|
+
init_node();
|
|
1526
|
+
init_web();
|
|
1527
|
+
init_pure();
|
|
1528
|
+
init_utils();
|
|
1529
|
+
init_PM_WithWebSocket();
|
|
1530
|
+
PM_WithBuild = class extends PM_WithWebSocket {
|
|
1531
|
+
constructor(configs, name, mode2) {
|
|
1532
|
+
super(configs);
|
|
1533
|
+
this.currentBuildResolve = null;
|
|
1534
|
+
this.currentBuildReject = null;
|
|
1535
|
+
this.configs = configs;
|
|
1536
|
+
this.name = name;
|
|
1537
|
+
this.mode = mode2;
|
|
1538
|
+
}
|
|
1539
|
+
async startBuildProcesses() {
|
|
1540
|
+
const { nodeEntryPoints, webEntryPoints, pureEntryPoints } = getRunnables(
|
|
1541
|
+
this.configs.tests,
|
|
1542
|
+
this.name
|
|
1543
|
+
);
|
|
1544
|
+
console.log(`Starting build processes for ${this.name}...`);
|
|
1545
|
+
console.log(` Node entry points: ${Object.keys(nodeEntryPoints).length}`);
|
|
1546
|
+
console.log(` Web entry points: ${Object.keys(webEntryPoints).length}`);
|
|
1547
|
+
console.log(` Pure entry points: ${Object.keys(pureEntryPoints).length}`);
|
|
1548
|
+
await Promise.all([
|
|
1549
|
+
this.startBuildProcess(node_default, nodeEntryPoints, "node"),
|
|
1550
|
+
this.startBuildProcess(web_default, webEntryPoints, "web"),
|
|
1551
|
+
this.startBuildProcess(pure_default, pureEntryPoints, "pure")
|
|
1552
|
+
]);
|
|
1553
|
+
}
|
|
1554
|
+
async startBuildProcess(configer, entryPoints, runtime) {
|
|
1555
|
+
const entryPointKeys = Object.keys(entryPoints);
|
|
1556
|
+
if (entryPointKeys.length === 0)
|
|
1557
|
+
return;
|
|
1558
|
+
const self = this;
|
|
1559
|
+
const buildProcessTrackerPlugin = {
|
|
1560
|
+
name: "build-process-tracker",
|
|
1561
|
+
setup(build) {
|
|
1562
|
+
build.onStart(() => {
|
|
1563
|
+
const processId = `build-${runtime}-${Date.now()}`;
|
|
1564
|
+
const command = `esbuild ${runtime} for ${self.name}`;
|
|
1565
|
+
const buildPromise = new Promise((resolve, reject) => {
|
|
1566
|
+
self.currentBuildResolve = resolve;
|
|
1567
|
+
self.currentBuildReject = reject;
|
|
1568
|
+
});
|
|
1569
|
+
if (self.addPromiseProcess) {
|
|
1570
|
+
self.addPromiseProcess(
|
|
1571
|
+
processId,
|
|
1572
|
+
buildPromise,
|
|
1573
|
+
command,
|
|
1574
|
+
"build-time",
|
|
1575
|
+
self.name,
|
|
1576
|
+
runtime
|
|
1577
|
+
);
|
|
1578
|
+
}
|
|
1579
|
+
console.log(`Starting ${runtime} build for ${entryPointKeys.length} entry points`);
|
|
1580
|
+
if (self.broadcast) {
|
|
1581
|
+
self.broadcast({
|
|
1582
|
+
type: "buildEvent",
|
|
1583
|
+
event: "start",
|
|
1584
|
+
runtime,
|
|
1585
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1586
|
+
entryPoints: entryPointKeys.length,
|
|
1587
|
+
processId
|
|
1588
|
+
});
|
|
1589
|
+
}
|
|
1590
|
+
});
|
|
1591
|
+
build.onEnd((result) => {
|
|
1592
|
+
const event = {
|
|
1593
|
+
type: "buildEvent",
|
|
1594
|
+
event: result.errors.length > 0 ? "error" : "success",
|
|
1595
|
+
runtime,
|
|
1596
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1597
|
+
errors: result.errors.length,
|
|
1598
|
+
warnings: result.warnings.length
|
|
1599
|
+
};
|
|
1600
|
+
if (result.errors.length > 0) {
|
|
1601
|
+
console.error(`Build ${runtime} failed with ${result.errors.length} errors`);
|
|
1602
|
+
if (self.currentBuildReject) {
|
|
1603
|
+
self.currentBuildReject(new Error(`Build failed with ${result.errors.length} errors`));
|
|
1604
|
+
}
|
|
1605
|
+
} else {
|
|
1606
|
+
console.log(`Build ${runtime} completed successfully`);
|
|
1607
|
+
if (self.currentBuildResolve) {
|
|
1608
|
+
self.currentBuildResolve();
|
|
1609
|
+
}
|
|
1610
|
+
}
|
|
1611
|
+
if (self.broadcast) {
|
|
1612
|
+
self.broadcast(event);
|
|
1613
|
+
}
|
|
1614
|
+
self.currentBuildResolve = null;
|
|
1615
|
+
self.currentBuildReject = null;
|
|
1616
|
+
});
|
|
1617
|
+
}
|
|
1618
|
+
};
|
|
1619
|
+
const baseConfig = configer(this.configs, entryPointKeys, this.name);
|
|
1620
|
+
const configWithPlugin = {
|
|
1621
|
+
...baseConfig,
|
|
1622
|
+
plugins: [...baseConfig.plugins || [], buildProcessTrackerPlugin]
|
|
1623
|
+
};
|
|
1624
|
+
try {
|
|
1625
|
+
const ctx = await esbuild.context(configWithPlugin);
|
|
1626
|
+
if (this.mode === "dev") {
|
|
1627
|
+
await ctx.watch();
|
|
1628
|
+
} else {
|
|
1629
|
+
const result = await ctx.rebuild();
|
|
1630
|
+
await ctx.dispose();
|
|
1631
|
+
}
|
|
1632
|
+
} catch (error) {
|
|
1633
|
+
console.error(`Failed to start ${runtime} build context:`, error);
|
|
1634
|
+
if (this.broadcast) {
|
|
1635
|
+
this.broadcast({
|
|
1636
|
+
type: "buildEvent",
|
|
1637
|
+
event: "error",
|
|
1638
|
+
runtime,
|
|
1639
|
+
timestamp: (/* @__PURE__ */ new Date()).toISOString(),
|
|
1640
|
+
errors: 1,
|
|
1641
|
+
warnings: 0,
|
|
1642
|
+
message: error.message
|
|
1643
|
+
});
|
|
1644
|
+
}
|
|
1645
|
+
}
|
|
1646
|
+
}
|
|
1647
|
+
};
|
|
1648
|
+
}
|
|
1649
|
+
});
|
|
1650
|
+
|
|
1651
|
+
// src/utils/logFiles.ts
|
|
1652
|
+
function getLogFilesForRuntime(runtime) {
|
|
1653
|
+
const { standard, runtimeSpecific } = getRuntimeLogs(runtime);
|
|
1654
|
+
return [...standard, ...runtimeSpecific];
|
|
1655
|
+
}
|
|
1656
|
+
var LOG_FILES, STANDARD_LOGS, RUNTIME_SPECIFIC_LOGS, ALL_LOGS, getRuntimeLogs;
|
|
1657
|
+
var init_logFiles = __esm({
|
|
1658
|
+
"src/utils/logFiles.ts"() {
|
|
1659
|
+
"use strict";
|
|
1660
|
+
LOG_FILES = {
|
|
1661
|
+
TESTS: "tests.json",
|
|
1662
|
+
TYPE_ERRORS: "type_errors.txt",
|
|
1663
|
+
LINT_ERRORS: "lint_errors.txt",
|
|
1664
|
+
EXIT: "exit.log",
|
|
1665
|
+
MESSAGE: "message.txt",
|
|
1666
|
+
PROMPT: "prompt.txt",
|
|
1667
|
+
STDOUT: "stdout.log",
|
|
1668
|
+
STDERR: "stderr.log",
|
|
1669
|
+
INFO: "info.log",
|
|
1670
|
+
ERROR: "error.log",
|
|
1671
|
+
WARN: "warn.log",
|
|
1672
|
+
DEBUG: "debug.log"
|
|
1673
|
+
};
|
|
1674
|
+
STANDARD_LOGS = {
|
|
1675
|
+
TESTS: "tests.json",
|
|
1676
|
+
TYPE_ERRORS: "type_errors.txt",
|
|
1677
|
+
LINT_ERRORS: "lint_errors.txt",
|
|
1678
|
+
EXIT: "exit.log",
|
|
1679
|
+
MESSAGE: "message.txt",
|
|
1680
|
+
PROMPT: "prompt.txt",
|
|
1681
|
+
BUILD: "build.json"
|
|
1682
|
+
};
|
|
1683
|
+
RUNTIME_SPECIFIC_LOGS = {
|
|
1684
|
+
node: {
|
|
1685
|
+
STDOUT: "stdout.log",
|
|
1686
|
+
STDERR: "stderr.log"
|
|
1687
|
+
},
|
|
1688
|
+
web: {
|
|
1689
|
+
INFO: "info.log",
|
|
1690
|
+
ERROR: "error.log",
|
|
1691
|
+
WARN: "warn.log",
|
|
1692
|
+
DEBUG: "debug.log"
|
|
1693
|
+
},
|
|
1694
|
+
pure: {}
|
|
1695
|
+
// No runtime-specific logs for pure
|
|
1696
|
+
};
|
|
1697
|
+
ALL_LOGS = {
|
|
1698
|
+
...STANDARD_LOGS,
|
|
1699
|
+
...Object.values(RUNTIME_SPECIFIC_LOGS).reduce((acc, logs) => ({ ...acc, ...logs }), {})
|
|
1700
|
+
};
|
|
1701
|
+
getRuntimeLogs = (runtime) => {
|
|
1702
|
+
return {
|
|
1703
|
+
standard: Object.values(STANDARD_LOGS),
|
|
1704
|
+
runtimeSpecific: Object.values(RUNTIME_SPECIFIC_LOGS[runtime])
|
|
1705
|
+
};
|
|
1706
|
+
};
|
|
1707
|
+
}
|
|
1708
|
+
});
|
|
1709
|
+
|
|
1710
|
+
// src/utils/makePrompt.ts
|
|
1711
|
+
import fs7 from "fs";
|
|
1712
|
+
import path7 from "path";
|
|
1713
|
+
var makePrompt, makePromptInternal;
|
|
1714
|
+
var init_makePrompt = __esm({
|
|
1715
|
+
"src/utils/makePrompt.ts"() {
|
|
1716
|
+
"use strict";
|
|
1717
|
+
init_utils();
|
|
1718
|
+
init_logFiles();
|
|
1719
|
+
init_logFiles();
|
|
1720
|
+
makePrompt = async (summary, name, entryPoint, addableFiles, runtime) => {
|
|
1721
|
+
summary[entryPoint].prompt = "?";
|
|
1722
|
+
const promptPath = promptPather(entryPoint, runtime, name);
|
|
1723
|
+
const testDir = path7.join(
|
|
1724
|
+
"testeranto",
|
|
1725
|
+
"reports",
|
|
1726
|
+
name,
|
|
1727
|
+
entryPoint.split(".").slice(0, -1).join("."),
|
|
1728
|
+
runtime
|
|
1729
|
+
);
|
|
1730
|
+
if (!fs7.existsSync(testDir)) {
|
|
1731
|
+
fs7.mkdirSync(testDir, { recursive: true });
|
|
1732
|
+
}
|
|
1733
|
+
const testPaths = path7.join(testDir, LOG_FILES.TESTS);
|
|
1734
|
+
const lintPath = path7.join(testDir, LOG_FILES.LINT_ERRORS);
|
|
1735
|
+
const typePath = path7.join(testDir, LOG_FILES.TYPE_ERRORS);
|
|
1736
|
+
const messagePath = path7.join(testDir, LOG_FILES.MESSAGE);
|
|
1737
|
+
try {
|
|
1738
|
+
await Promise.all([
|
|
1739
|
+
fs7.promises.writeFile(
|
|
1740
|
+
promptPath,
|
|
1741
|
+
`
|
|
1742
|
+
${addableFiles.map((x) => {
|
|
1743
|
+
return `/add ${x}`;
|
|
1744
|
+
}).join("\n")}
|
|
1745
|
+
|
|
1746
|
+
/read node_modules/testeranto/docs/index.md
|
|
1747
|
+
/read node_modules/testeranto/docs/style.md
|
|
1748
|
+
/read node_modules/testeranto/docs/testing.ai.txt
|
|
1749
|
+
/read node_modules/testeranto/src/CoreTypes.ts
|
|
1750
|
+
|
|
1751
|
+
/read ${testPaths}
|
|
1752
|
+
/read ${typePath}
|
|
1753
|
+
/read ${lintPath}
|
|
1754
|
+
|
|
1755
|
+
/read ${getLogFilesForRuntime(runtime).map((p) => `${testDir}/${p}`).join(" ")}
|
|
1756
|
+
`
|
|
1757
|
+
),
|
|
1758
|
+
fs7.promises.writeFile(
|
|
1759
|
+
messagePath,
|
|
1760
|
+
`
|
|
1761
|
+
There are 3 types of test reports.
|
|
1762
|
+
1) bdd (highest priority)
|
|
1763
|
+
2) type checker
|
|
1764
|
+
3) static analysis (lowest priority)
|
|
1765
|
+
|
|
1766
|
+
"tests.json" is the detailed result of the bdd tests.
|
|
1767
|
+
if these files do not exist, then something has gone badly wrong and needs to be addressed.
|
|
1768
|
+
|
|
1769
|
+
"type_errors.txt" is the result of the type checker.
|
|
1770
|
+
if this file does not exist, then type check passed without errors;
|
|
1771
|
+
|
|
1772
|
+
"lint_errors.txt" is the result of the static analysis.
|
|
1773
|
+
if this file does not exist, then static analysis passed without errors;
|
|
1774
|
+
|
|
1775
|
+
BDD failures are the highest priority. Focus on passing BDD tests before addressing other concerns.
|
|
1776
|
+
Do not add error throwing/catching to the tests themselves.
|
|
1777
|
+
`
|
|
1778
|
+
)
|
|
1779
|
+
]);
|
|
1780
|
+
} catch (e) {
|
|
1781
|
+
console.error(`Failed to write prompt files at ${testDir}`);
|
|
1782
|
+
console.error(e);
|
|
1783
|
+
throw e;
|
|
1784
|
+
}
|
|
1785
|
+
summary[entryPoint].prompt = `aider --model deepseek/deepseek-chat --load testeranto/${name}/reports/${runtime}/${entryPoint.split(".").slice(0, -1).join(".")}/prompt.txt`;
|
|
1786
|
+
};
|
|
1787
|
+
makePromptInternal = (summary, name, entryPoint, addableFiles, runTime) => {
|
|
1788
|
+
if (runTime === "node") {
|
|
1789
|
+
return makePrompt(summary, name, entryPoint, addableFiles, "node");
|
|
1790
|
+
}
|
|
1791
|
+
if (runTime === "web") {
|
|
1792
|
+
return makePrompt(summary, name, entryPoint, addableFiles, "web");
|
|
1793
|
+
}
|
|
1794
|
+
if (runTime === "pure") {
|
|
1795
|
+
return makePrompt(summary, name, entryPoint, addableFiles, "pure");
|
|
1796
|
+
}
|
|
1797
|
+
};
|
|
1798
|
+
}
|
|
1799
|
+
});
|
|
1800
|
+
|
|
1801
|
+
// src/PM/PM_WithEslintAndTsc.ts
|
|
1802
|
+
import ts from "typescript";
|
|
1803
|
+
import fs8 from "fs";
|
|
1804
|
+
import ansiC2 from "ansi-colors";
|
|
1805
|
+
import { ESLint } from "eslint";
|
|
1806
|
+
import tsc from "tsc-prog";
|
|
1807
|
+
var eslint, formatter, PM_WithEslintAndTsc;
|
|
1808
|
+
var init_PM_WithEslintAndTsc = __esm({
|
|
1809
|
+
async "src/PM/PM_WithEslintAndTsc.ts"() {
|
|
1810
|
+
"use strict";
|
|
1811
|
+
init_utils();
|
|
1812
|
+
init_PM_WithBuild();
|
|
1813
|
+
init_makePrompt();
|
|
1814
|
+
eslint = new ESLint();
|
|
1815
|
+
formatter = await eslint.loadFormatter(
|
|
1816
|
+
"./node_modules/testeranto/dist/prebuild/esbuildConfigs/eslint-formatter-testeranto.mjs"
|
|
1817
|
+
);
|
|
1818
|
+
PM_WithEslintAndTsc = class extends PM_WithBuild {
|
|
1819
|
+
constructor(configs, name, mode2) {
|
|
1820
|
+
super(configs, name, mode2);
|
|
1821
|
+
this.summary = {};
|
|
1822
|
+
this.tscCheck = async ({
|
|
1823
|
+
entrypoint,
|
|
1824
|
+
addableFiles,
|
|
1825
|
+
platform
|
|
1826
|
+
}) => {
|
|
1827
|
+
const processId = `tsc-${entrypoint}-${Date.now()}`;
|
|
1828
|
+
const command = `tsc check for ${entrypoint}`;
|
|
1829
|
+
const tscPromise = (async () => {
|
|
1830
|
+
try {
|
|
1831
|
+
this.typeCheckIsRunning(entrypoint);
|
|
1832
|
+
} catch (e) {
|
|
1833
|
+
throw new Error(`Error in tscCheck: ${e.message}`);
|
|
1834
|
+
}
|
|
1835
|
+
const program = tsc.createProgramFromConfig({
|
|
1836
|
+
basePath: process.cwd(),
|
|
1837
|
+
configFilePath: "tsconfig.json",
|
|
1838
|
+
compilerOptions: {
|
|
1839
|
+
outDir: tscPather(entrypoint, platform, this.name),
|
|
1840
|
+
noEmit: true
|
|
1841
|
+
},
|
|
1842
|
+
include: addableFiles
|
|
1843
|
+
});
|
|
1844
|
+
const tscPath = tscPather(entrypoint, platform, this.name);
|
|
1845
|
+
const allDiagnostics = program.getSemanticDiagnostics();
|
|
1846
|
+
const results = [];
|
|
1847
|
+
allDiagnostics.forEach((diagnostic) => {
|
|
1848
|
+
if (diagnostic.file) {
|
|
1849
|
+
const { line, character } = ts.getLineAndCharacterOfPosition(
|
|
1850
|
+
diagnostic.file,
|
|
1851
|
+
diagnostic.start
|
|
1852
|
+
);
|
|
1853
|
+
const message = ts.flattenDiagnosticMessageText(
|
|
1854
|
+
diagnostic.messageText,
|
|
1855
|
+
"\n"
|
|
1856
|
+
);
|
|
1857
|
+
results.push(
|
|
1858
|
+
`${diagnostic.file.fileName} (${line + 1},${character + 1}): ${message}`
|
|
1859
|
+
);
|
|
1860
|
+
} else {
|
|
1861
|
+
results.push(
|
|
1862
|
+
ts.flattenDiagnosticMessageText(diagnostic.messageText, "\n")
|
|
1863
|
+
);
|
|
1864
|
+
}
|
|
1865
|
+
});
|
|
1866
|
+
fs8.writeFileSync(tscPath, results.join("\n"));
|
|
1867
|
+
this.typeCheckIsNowDone(entrypoint, results.length);
|
|
1868
|
+
return results.length;
|
|
1869
|
+
})();
|
|
1870
|
+
if (this.addPromiseProcess) {
|
|
1871
|
+
this.addPromiseProcess(
|
|
1872
|
+
processId,
|
|
1873
|
+
tscPromise,
|
|
1874
|
+
command,
|
|
1875
|
+
"build-time",
|
|
1876
|
+
entrypoint
|
|
1877
|
+
);
|
|
1878
|
+
} else {
|
|
1879
|
+
await tscPromise;
|
|
1880
|
+
}
|
|
1881
|
+
};
|
|
1882
|
+
this.eslintCheck = async (entrypoint, platform, addableFiles) => {
|
|
1883
|
+
const processId = `eslint-${entrypoint}-${Date.now()}`;
|
|
1884
|
+
const command = `eslint check for ${entrypoint}`;
|
|
1885
|
+
const eslintPromise = (async () => {
|
|
1886
|
+
try {
|
|
1887
|
+
this.lintIsRunning(entrypoint);
|
|
1888
|
+
} catch (e) {
|
|
1889
|
+
throw new Error(`Error in eslintCheck: ${e.message}`);
|
|
1890
|
+
}
|
|
1891
|
+
const filepath = lintPather(entrypoint, platform, this.name);
|
|
1892
|
+
if (fs8.existsSync(filepath))
|
|
1893
|
+
fs8.rmSync(filepath);
|
|
1894
|
+
const results = (await eslint.lintFiles(addableFiles)).filter((r) => r.messages.length).filter((r) => {
|
|
1895
|
+
return r.messages[0].ruleId !== null;
|
|
1896
|
+
}).map((r) => {
|
|
1897
|
+
delete r.source;
|
|
1898
|
+
return r;
|
|
1899
|
+
});
|
|
1900
|
+
fs8.writeFileSync(filepath, await formatter.format(results));
|
|
1901
|
+
this.lintIsNowDone(entrypoint, results.length);
|
|
1902
|
+
return results.length;
|
|
1903
|
+
})();
|
|
1904
|
+
if (this.addPromiseProcess) {
|
|
1905
|
+
this.addPromiseProcess(
|
|
1906
|
+
processId,
|
|
1907
|
+
eslintPromise,
|
|
1908
|
+
command,
|
|
1909
|
+
"build-time",
|
|
1910
|
+
entrypoint
|
|
1911
|
+
);
|
|
1912
|
+
} else {
|
|
1913
|
+
await eslintPromise;
|
|
1914
|
+
}
|
|
1915
|
+
};
|
|
1916
|
+
this.makePrompt = async (entryPoint, addableFiles, platform) => {
|
|
1917
|
+
await makePromptInternal(
|
|
1918
|
+
this.summary,
|
|
1919
|
+
this.name,
|
|
1920
|
+
entryPoint,
|
|
1921
|
+
addableFiles,
|
|
1922
|
+
platform
|
|
1923
|
+
);
|
|
1924
|
+
this.checkForShutdown();
|
|
1925
|
+
};
|
|
1926
|
+
this.typeCheckIsRunning = (src) => {
|
|
1927
|
+
if (!this.summary[src]) {
|
|
1928
|
+
throw `this.summary[${src}] is undefined`;
|
|
1929
|
+
}
|
|
1930
|
+
this.summary[src].typeErrors = "?";
|
|
1931
|
+
};
|
|
1932
|
+
this.typeCheckIsNowDone = (src, failures) => {
|
|
1933
|
+
if (!this.summary[src]) {
|
|
1934
|
+
throw `this.summary[${src}] is undefined`;
|
|
1935
|
+
}
|
|
1936
|
+
if (failures === 0) {
|
|
1937
|
+
console.log(ansiC2.green(ansiC2.inverse(`tsc > ${src}`)));
|
|
1938
|
+
} else {
|
|
1939
|
+
console.log(
|
|
1940
|
+
ansiC2.red(ansiC2.inverse(`tsc > ${src} failed ${failures} times`))
|
|
1941
|
+
);
|
|
1942
|
+
}
|
|
1943
|
+
this.summary[src].typeErrors = failures;
|
|
1944
|
+
this.writeBigBoard();
|
|
1945
|
+
this.checkForShutdown();
|
|
1946
|
+
};
|
|
1947
|
+
this.lintIsRunning = (src) => {
|
|
1948
|
+
if (!this.summary[src]) {
|
|
1949
|
+
throw `this.summary[${src}] is undefined`;
|
|
1950
|
+
}
|
|
1951
|
+
this.summary[src].staticErrors = "?";
|
|
1952
|
+
this.writeBigBoard();
|
|
1953
|
+
};
|
|
1954
|
+
this.lintIsNowDone = (src, failures) => {
|
|
1955
|
+
if (!this.summary[src]) {
|
|
1956
|
+
throw `this.summary[${src}] is undefined`;
|
|
1957
|
+
}
|
|
1958
|
+
if (failures === 0) {
|
|
1959
|
+
console.log(ansiC2.green(ansiC2.inverse(`eslint > ${src}`)));
|
|
1960
|
+
} else {
|
|
1961
|
+
console.log(
|
|
1962
|
+
ansiC2.red(ansiC2.inverse(`eslint > ${src} failed ${failures} times`))
|
|
1963
|
+
);
|
|
1964
|
+
}
|
|
1965
|
+
this.summary[src].staticErrors = failures;
|
|
1966
|
+
this.writeBigBoard();
|
|
1967
|
+
this.checkForShutdown();
|
|
1968
|
+
};
|
|
1969
|
+
this.bddTestIsRunning = (src) => {
|
|
1970
|
+
if (!this.summary[src]) {
|
|
1971
|
+
throw `this.summary[${src}] is undefined`;
|
|
1972
|
+
}
|
|
1973
|
+
this.summary[src].runTimeErrors = "?";
|
|
1974
|
+
this.writeBigBoard();
|
|
1975
|
+
};
|
|
1976
|
+
this.bddTestIsNowDone = (src, failures) => {
|
|
1977
|
+
if (!this.summary[src]) {
|
|
1978
|
+
throw `this.summary[${src}] is undefined`;
|
|
1979
|
+
}
|
|
1980
|
+
this.summary[src].runTimeErrors = failures;
|
|
1981
|
+
this.writeBigBoard();
|
|
1982
|
+
this.checkForShutdown();
|
|
1983
|
+
};
|
|
1984
|
+
this.writeBigBoard = () => {
|
|
1985
|
+
const summaryPath = `./testeranto/reports/${this.name}/summary.json`;
|
|
1986
|
+
const summaryData = JSON.stringify(this.summary, null, 2);
|
|
1987
|
+
fs8.writeFileSync(summaryPath, summaryData);
|
|
1988
|
+
this.broadcast({
|
|
1989
|
+
type: "summaryUpdate",
|
|
1990
|
+
data: this.summary
|
|
1991
|
+
});
|
|
1992
|
+
};
|
|
1993
|
+
this.summary = {};
|
|
1994
|
+
this.configs.tests.forEach(([t, rt, tr, sidecars]) => {
|
|
1995
|
+
this.ensureSummaryEntry(t);
|
|
1996
|
+
sidecars.forEach(([sidecarName]) => {
|
|
1997
|
+
this.ensureSummaryEntry(sidecarName, true);
|
|
1998
|
+
});
|
|
1999
|
+
});
|
|
2000
|
+
}
|
|
2001
|
+
ensureSummaryEntry(src, isSidecar = false) {
|
|
2002
|
+
if (!this.summary[src]) {
|
|
2003
|
+
this.summary[src] = {
|
|
2004
|
+
typeErrors: void 0,
|
|
2005
|
+
staticErrors: void 0,
|
|
2006
|
+
runTimeErrors: void 0,
|
|
2007
|
+
prompt: void 0,
|
|
2008
|
+
failingFeatures: {}
|
|
2009
|
+
};
|
|
2010
|
+
if (isSidecar) {
|
|
2011
|
+
}
|
|
2012
|
+
}
|
|
2013
|
+
return this.summary[src];
|
|
2014
|
+
}
|
|
2015
|
+
};
|
|
2016
|
+
}
|
|
2017
|
+
});
|
|
2018
|
+
|
|
2019
|
+
// src/PM/PM_WithGit.ts
|
|
2020
|
+
import url2 from "url";
|
|
2021
|
+
var PM_WithGit;
|
|
2022
|
+
var init_PM_WithGit = __esm({
|
|
2023
|
+
async "src/PM/PM_WithGit.ts"() {
|
|
2024
|
+
"use strict";
|
|
2025
|
+
await init_PM_WithEslintAndTsc();
|
|
2026
|
+
PM_WithGit = class extends PM_WithEslintAndTsc {
|
|
2027
|
+
constructor(configs, name, mode2) {
|
|
2028
|
+
super(configs, name, mode2);
|
|
2029
|
+
this.gitWatchTimeout = null;
|
|
2030
|
+
this.gitWatcher = null;
|
|
2031
|
+
}
|
|
2032
|
+
// Override requestHandler to add Git-specific endpoints
|
|
2033
|
+
requestHandler(req, res) {
|
|
2034
|
+
const parsedUrl = url2.parse(req.url || "/");
|
|
2035
|
+
const pathname = parsedUrl.pathname || "/";
|
|
2036
|
+
if (pathname?.startsWith("/api/git/")) {
|
|
2037
|
+
this.handleGitApi(req, res);
|
|
2038
|
+
return;
|
|
2039
|
+
}
|
|
2040
|
+
if (pathname === "/api/auth/github/token" && req.method === "POST") {
|
|
2041
|
+
this.handleGitHubTokenExchange(req, res);
|
|
2042
|
+
return;
|
|
2043
|
+
}
|
|
2044
|
+
if (pathname === "/auth/github/callback") {
|
|
2045
|
+
const callbackHtml = `
|
|
2046
|
+
<!DOCTYPE html>
|
|
2047
|
+
<html>
|
|
2048
|
+
<head>
|
|
2049
|
+
<title>GitHub Authentication - Testeranto</title>
|
|
2050
|
+
<script>
|
|
2051
|
+
// Extract the code from the URL and send it to the parent window
|
|
2052
|
+
const urlParams = new URLSearchParams(window.location.search);
|
|
2053
|
+
const code = urlParams.get('code');
|
|
2054
|
+
const error = urlParams.get('error');
|
|
2055
|
+
|
|
2056
|
+
if (code) {
|
|
2057
|
+
window.opener.postMessage({ type: 'github-auth-callback', code }, '*');
|
|
2058
|
+
} else if (error) {
|
|
2059
|
+
window.opener.postMessage({ type: 'github-auth-error', error }, '*');
|
|
2060
|
+
}
|
|
2061
|
+
window.close();
|
|
2062
|
+
</script>
|
|
2063
|
+
</head>
|
|
2064
|
+
<body>
|
|
2065
|
+
<p>Completing authentication...</p>
|
|
2066
|
+
</body>
|
|
2067
|
+
</html>`;
|
|
2068
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
2069
|
+
res.end(callbackHtml);
|
|
2070
|
+
return;
|
|
2071
|
+
}
|
|
2072
|
+
super.requestHandler(req, res);
|
|
2073
|
+
}
|
|
2074
|
+
// this method is also horrible
|
|
2075
|
+
handleGitApi(req, res) {
|
|
2076
|
+
const parsedUrl = url2.parse(req.url || "/");
|
|
2077
|
+
const pathname = parsedUrl.pathname || "/";
|
|
2078
|
+
res.setHeader("Access-Control-Allow-Origin", "*");
|
|
2079
|
+
res.setHeader("Access-Control-Allow-Methods", "GET, POST, OPTIONS");
|
|
2080
|
+
res.setHeader("Access-Control-Allow-Headers", "Content-Type");
|
|
2081
|
+
if (req.method === "OPTIONS") {
|
|
2082
|
+
res.writeHead(200);
|
|
2083
|
+
res.end();
|
|
2084
|
+
return;
|
|
2085
|
+
}
|
|
2086
|
+
try {
|
|
2087
|
+
if (pathname === "/api/git/changes" && req.method === "GET") {
|
|
2088
|
+
this.handleGitChanges(req, res);
|
|
2089
|
+
} else if (pathname === "/api/git/status" && req.method === "GET") {
|
|
2090
|
+
this.handleGitFileStatus(req, res);
|
|
2091
|
+
} else if (pathname === "/api/git/commit" && req.method === "POST") {
|
|
2092
|
+
this.handleGitCommit(req, res);
|
|
2093
|
+
} else if (pathname === "/api/git/push" && req.method === "POST") {
|
|
2094
|
+
this.handleGitPush(req, res);
|
|
2095
|
+
} else if (pathname === "/api/git/pull" && req.method === "POST") {
|
|
2096
|
+
this.handleGitPull(req, res);
|
|
2097
|
+
} else if (pathname === "/api/git/branch" && req.method === "GET") {
|
|
2098
|
+
this.handleGitBranch(req, res);
|
|
2099
|
+
} else if (pathname === "/api/git/remote-status" && req.method === "GET") {
|
|
2100
|
+
this.handleGitRemoteStatus(req, res);
|
|
2101
|
+
} else {
|
|
2102
|
+
res.writeHead(404, { "Content-Type": "application/json" });
|
|
2103
|
+
res.end(JSON.stringify({ error: "Not found" }));
|
|
2104
|
+
}
|
|
2105
|
+
} catch (error) {
|
|
2106
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
2107
|
+
res.end(JSON.stringify({ error: "Internal server error" }));
|
|
2108
|
+
}
|
|
2109
|
+
}
|
|
2110
|
+
async handleGitChanges(req, res) {
|
|
2111
|
+
try {
|
|
2112
|
+
const changes2 = await this.getGitChanges();
|
|
2113
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
2114
|
+
res.end(JSON.stringify(changes2));
|
|
2115
|
+
} catch (error) {
|
|
2116
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
2117
|
+
res.end(JSON.stringify({ error: "Failed to get changes" }));
|
|
2118
|
+
}
|
|
2119
|
+
}
|
|
2120
|
+
async handleGitFileStatus(req, res) {
|
|
2121
|
+
const parsedUrl = url2.parse(req.url || "/");
|
|
2122
|
+
const query = parsedUrl.query || "";
|
|
2123
|
+
const params = new URLSearchParams(query);
|
|
2124
|
+
const path12 = params.get("path");
|
|
2125
|
+
if (!path12) {
|
|
2126
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
2127
|
+
res.end(JSON.stringify({ error: "Path parameter required" }));
|
|
2128
|
+
return;
|
|
2129
|
+
}
|
|
2130
|
+
try {
|
|
2131
|
+
const status = await this.getGitFileStatus(path12);
|
|
2132
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
2133
|
+
res.end(JSON.stringify(status));
|
|
2134
|
+
} catch (error) {
|
|
2135
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
2136
|
+
res.end(JSON.stringify({ error: "Failed to get file status" }));
|
|
2137
|
+
}
|
|
2138
|
+
}
|
|
2139
|
+
async handleGitCommit(req, res) {
|
|
2140
|
+
let body = "";
|
|
2141
|
+
req.on("data", (chunk) => {
|
|
2142
|
+
body += chunk.toString();
|
|
2143
|
+
});
|
|
2144
|
+
req.on("end", async () => {
|
|
2145
|
+
try {
|
|
2146
|
+
const { message, description } = JSON.parse(body);
|
|
2147
|
+
await this.executeGitCommit(message, description);
|
|
2148
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
2149
|
+
res.end(JSON.stringify({ success: true }));
|
|
2150
|
+
} catch (error) {
|
|
2151
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
2152
|
+
res.end(JSON.stringify({ error: "Failed to commit" }));
|
|
2153
|
+
}
|
|
2154
|
+
});
|
|
2155
|
+
}
|
|
2156
|
+
async handleGitPush(req, res) {
|
|
2157
|
+
try {
|
|
2158
|
+
await this.executeGitPush();
|
|
2159
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
2160
|
+
res.end(JSON.stringify({ success: true }));
|
|
2161
|
+
} catch (error) {
|
|
2162
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
2163
|
+
res.end(JSON.stringify({ error: "Failed to push" }));
|
|
2164
|
+
}
|
|
2165
|
+
}
|
|
2166
|
+
async handleGitPull(req, res) {
|
|
2167
|
+
try {
|
|
2168
|
+
await this.executeGitPull();
|
|
2169
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
2170
|
+
res.end(JSON.stringify({ success: true }));
|
|
2171
|
+
} catch (error) {
|
|
2172
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
2173
|
+
res.end(JSON.stringify({ error: "Failed to pull" }));
|
|
2174
|
+
}
|
|
2175
|
+
}
|
|
2176
|
+
async handleGitBranch(req, res) {
|
|
2177
|
+
try {
|
|
2178
|
+
const branch = await this.getCurrentGitBranch();
|
|
2179
|
+
res.writeHead(200, { "Content-Type": "text/plain" });
|
|
2180
|
+
res.end(branch);
|
|
2181
|
+
} catch (error) {
|
|
2182
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
2183
|
+
res.end(JSON.stringify({ error: "Failed to get branch" }));
|
|
2184
|
+
}
|
|
2185
|
+
}
|
|
2186
|
+
async handleGitHubTokenExchange(req, res) {
|
|
2187
|
+
let body = "";
|
|
2188
|
+
req.on("data", (chunk) => {
|
|
2189
|
+
body += chunk.toString();
|
|
2190
|
+
});
|
|
2191
|
+
req.on("end", async () => {
|
|
2192
|
+
try {
|
|
2193
|
+
const { code } = JSON.parse(body);
|
|
2194
|
+
const tokenResponse = await fetch(
|
|
2195
|
+
"https://github.com/login/oauth/access_token",
|
|
2196
|
+
{
|
|
2197
|
+
method: "POST",
|
|
2198
|
+
headers: {
|
|
2199
|
+
Accept: "application/json",
|
|
2200
|
+
"Content-Type": "application/json"
|
|
2201
|
+
},
|
|
2202
|
+
body: JSON.stringify({
|
|
2203
|
+
client_id: process.env.GITHUB_CLIENT_ID,
|
|
2204
|
+
client_secret: process.env.GITHUB_CLIENT_SECRET,
|
|
2205
|
+
code
|
|
2206
|
+
})
|
|
2207
|
+
}
|
|
2208
|
+
);
|
|
2209
|
+
const tokenData = await tokenResponse.json();
|
|
2210
|
+
if (tokenData.error) {
|
|
2211
|
+
res.writeHead(400, { "Content-Type": "application/json" });
|
|
2212
|
+
res.end(JSON.stringify({ error: tokenData.error_description }));
|
|
2213
|
+
return;
|
|
2214
|
+
}
|
|
2215
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
2216
|
+
res.end(JSON.stringify({ access_token: tokenData.access_token }));
|
|
2217
|
+
} catch (error) {
|
|
2218
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
2219
|
+
res.end(JSON.stringify({ error: "Failed to exchange token" }));
|
|
2220
|
+
}
|
|
2221
|
+
});
|
|
2222
|
+
}
|
|
2223
|
+
async handleGitRemoteStatus(req, res) {
|
|
2224
|
+
try {
|
|
2225
|
+
const status = await this.getGitRemoteStatus();
|
|
2226
|
+
res.writeHead(200, { "Content-Type": "application/json" });
|
|
2227
|
+
res.end(JSON.stringify(status));
|
|
2228
|
+
} catch (error) {
|
|
2229
|
+
res.writeHead(500, { "Content-Type": "application/json" });
|
|
2230
|
+
res.end(JSON.stringify({ error: "Failed to get remote status" }));
|
|
2231
|
+
}
|
|
2232
|
+
}
|
|
2233
|
+
async getGitFileStatus(path12) {
|
|
2234
|
+
try {
|
|
2235
|
+
const changes2 = await this.getGitChanges();
|
|
2236
|
+
const fileChange = changes2.find((change) => change.path === path12);
|
|
2237
|
+
if (fileChange) {
|
|
2238
|
+
return { status: fileChange.status };
|
|
2239
|
+
}
|
|
2240
|
+
return { status: "unchanged" };
|
|
2241
|
+
} catch (error) {
|
|
2242
|
+
console.error("Failed to get file status:", error);
|
|
2243
|
+
return { status: "unchanged" };
|
|
2244
|
+
}
|
|
2245
|
+
}
|
|
2246
|
+
async executeGitCommit(message, description) {
|
|
2247
|
+
try {
|
|
2248
|
+
const { exec } = await import("child_process");
|
|
2249
|
+
const fullMessage = description ? `${message}
|
|
2250
|
+
|
|
2251
|
+
${description}` : message;
|
|
2252
|
+
return new Promise((resolve, reject) => {
|
|
2253
|
+
exec("git add -A", { cwd: process.cwd() }, (error) => {
|
|
2254
|
+
if (error) {
|
|
2255
|
+
reject(new Error(`Failed to stage changes: ${error.message}`));
|
|
2256
|
+
return;
|
|
2257
|
+
}
|
|
2258
|
+
const commitCommand = `git commit -m "${fullMessage.replace(
|
|
2259
|
+
/"/g,
|
|
2260
|
+
'\\"'
|
|
2261
|
+
)}"`;
|
|
2262
|
+
exec(commitCommand, { cwd: process.cwd() }, (commitError) => {
|
|
2263
|
+
if (commitError) {
|
|
2264
|
+
reject(new Error(`Failed to commit: ${commitError.message}`));
|
|
2265
|
+
return;
|
|
2266
|
+
}
|
|
2267
|
+
resolve();
|
|
2268
|
+
});
|
|
2269
|
+
});
|
|
2270
|
+
});
|
|
2271
|
+
} catch (error) {
|
|
2272
|
+
throw new Error(
|
|
2273
|
+
`Failed to execute commit: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
2274
|
+
);
|
|
2275
|
+
}
|
|
2276
|
+
}
|
|
2277
|
+
async executeGitPush() {
|
|
2278
|
+
try {
|
|
2279
|
+
const { exec } = await import("child_process");
|
|
2280
|
+
return new Promise((resolve, reject) => {
|
|
2281
|
+
exec("git push", { cwd: process.cwd() }, (error) => {
|
|
2282
|
+
if (error) {
|
|
2283
|
+
reject(new Error(`Failed to push: ${error.message}`));
|
|
2284
|
+
return;
|
|
2285
|
+
}
|
|
2286
|
+
resolve();
|
|
2287
|
+
});
|
|
2288
|
+
});
|
|
2289
|
+
} catch (error) {
|
|
2290
|
+
throw new Error(
|
|
2291
|
+
`Failed to execute push: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
2292
|
+
);
|
|
2293
|
+
}
|
|
2294
|
+
}
|
|
2295
|
+
async executeGitPull() {
|
|
2296
|
+
try {
|
|
2297
|
+
const { exec } = await import("child_process");
|
|
2298
|
+
return new Promise((resolve, reject) => {
|
|
2299
|
+
exec("git pull", { cwd: process.cwd() }, (error) => {
|
|
2300
|
+
if (error) {
|
|
2301
|
+
reject(new Error(`Failed to pull: ${error.message}`));
|
|
2302
|
+
return;
|
|
2303
|
+
}
|
|
2304
|
+
resolve();
|
|
2305
|
+
});
|
|
2306
|
+
});
|
|
2307
|
+
} catch (error) {
|
|
2308
|
+
throw new Error(
|
|
2309
|
+
`Failed to execute pull: ${error instanceof Error ? error.message : "Unknown error"}`
|
|
2310
|
+
);
|
|
2311
|
+
}
|
|
2312
|
+
}
|
|
2313
|
+
// private async sendInitialState(ws: WebSocket) {
|
|
2314
|
+
// try {
|
|
2315
|
+
// const changes = await this.getGitChanges();
|
|
2316
|
+
// const status = await this.getGitRemoteStatus();
|
|
2317
|
+
// const branch = await this.getCurrentGitBranch();
|
|
2318
|
+
// ws.send(JSON.stringify({ type: "changes", changes }));
|
|
2319
|
+
// ws.send(JSON.stringify({ type: "status", status }));
|
|
2320
|
+
// ws.send(JSON.stringify({ type: "branch", branch }));
|
|
2321
|
+
// } catch (error) {
|
|
2322
|
+
// console.error("Error sending initial state:", error);
|
|
2323
|
+
// ws.send(
|
|
2324
|
+
// JSON.stringify({
|
|
2325
|
+
// type: "error",
|
|
2326
|
+
// message: "Failed to get Git status",
|
|
2327
|
+
// })
|
|
2328
|
+
// );
|
|
2329
|
+
// }
|
|
2330
|
+
// }
|
|
2331
|
+
// private async refreshGitStatus() {
|
|
2332
|
+
// try {
|
|
2333
|
+
// const changes = await this.getGitChanges();
|
|
2334
|
+
// const status = await this.getGitRemoteStatus();
|
|
2335
|
+
// const branch = await this.getCurrentGitBranch();
|
|
2336
|
+
// this.broadcast({ type: "changes", changes });
|
|
2337
|
+
// this.broadcast({ type: "status", status });
|
|
2338
|
+
// this.broadcast({ type: "branch", branch });
|
|
2339
|
+
// } catch (error) {
|
|
2340
|
+
// console.error("Error refreshing Git status:", error);
|
|
2341
|
+
// }
|
|
2342
|
+
// }
|
|
2343
|
+
onBuildDone() {
|
|
2344
|
+
console.log("Build processes completed");
|
|
2345
|
+
this.startGitWatcher();
|
|
2346
|
+
}
|
|
2347
|
+
async startGitWatcher() {
|
|
2348
|
+
console.log("Starting Git watcher for real-time updates");
|
|
2349
|
+
const watcher = (await import("fs")).watch(
|
|
2350
|
+
process.cwd(),
|
|
2351
|
+
{ recursive: true },
|
|
2352
|
+
async (eventType, filename) => {
|
|
2353
|
+
if (filename && !filename.includes(".git")) {
|
|
2354
|
+
try {
|
|
2355
|
+
clearTimeout(this.gitWatchTimeout);
|
|
2356
|
+
this.gitWatchTimeout = setTimeout(async () => {
|
|
2357
|
+
const changes2 = await this.getGitChanges();
|
|
2358
|
+
const status = await this.getGitRemoteStatus();
|
|
2359
|
+
const branch = await this.getCurrentGitBranch();
|
|
2360
|
+
this.broadcast({ type: "changes", changes: changes2 });
|
|
2361
|
+
this.broadcast({ type: "status", status });
|
|
2362
|
+
this.broadcast({ type: "branch", branch });
|
|
2363
|
+
}, 500);
|
|
2364
|
+
} catch (error) {
|
|
2365
|
+
console.error("Error checking Git status:", error);
|
|
2366
|
+
}
|
|
2367
|
+
}
|
|
2368
|
+
}
|
|
2369
|
+
);
|
|
2370
|
+
setInterval(async () => {
|
|
2371
|
+
try {
|
|
2372
|
+
const changes2 = await this.getGitChanges();
|
|
2373
|
+
const status = await this.getGitRemoteStatus();
|
|
2374
|
+
const branch = await this.getCurrentGitBranch();
|
|
2375
|
+
this.broadcast({ type: "changes", changes: changes2 });
|
|
2376
|
+
this.broadcast({ type: "status", status });
|
|
2377
|
+
this.broadcast({ type: "branch", branch });
|
|
2378
|
+
} catch (error) {
|
|
2379
|
+
console.error("Error checking Git status:", error);
|
|
2380
|
+
}
|
|
2381
|
+
}, 1e4);
|
|
2382
|
+
this.gitWatcher = watcher;
|
|
2383
|
+
}
|
|
2384
|
+
async getGitChanges() {
|
|
2385
|
+
try {
|
|
2386
|
+
const { exec } = await import("child_process");
|
|
2387
|
+
return new Promise((resolve, reject) => {
|
|
2388
|
+
exec(
|
|
2389
|
+
"git status --porcelain",
|
|
2390
|
+
{ cwd: process.cwd() },
|
|
2391
|
+
(error, stdout, stderr) => {
|
|
2392
|
+
if (error) {
|
|
2393
|
+
console.error("Error getting git changes:", error);
|
|
2394
|
+
resolve([]);
|
|
2395
|
+
return;
|
|
2396
|
+
}
|
|
2397
|
+
const changes2 = [];
|
|
2398
|
+
const lines = stdout.trim().split("\n");
|
|
2399
|
+
for (const line of lines) {
|
|
2400
|
+
if (!line.trim())
|
|
2401
|
+
continue;
|
|
2402
|
+
const status = line.substring(0, 2).trim();
|
|
2403
|
+
const path12 = line.substring(3).trim();
|
|
2404
|
+
let fileStatus = "unchanged";
|
|
2405
|
+
if (status.startsWith("M")) {
|
|
2406
|
+
fileStatus = "modified";
|
|
2407
|
+
} else if (status.startsWith("A")) {
|
|
2408
|
+
fileStatus = "added";
|
|
2409
|
+
} else if (status.startsWith("D")) {
|
|
2410
|
+
fileStatus = "deleted";
|
|
2411
|
+
} else if (status.startsWith("U") || status.includes("U")) {
|
|
2412
|
+
fileStatus = "conflicted";
|
|
2413
|
+
} else if (status.startsWith("??")) {
|
|
2414
|
+
fileStatus = "added";
|
|
2415
|
+
}
|
|
2416
|
+
if (fileStatus !== "unchanged") {
|
|
2417
|
+
changes2.push({
|
|
2418
|
+
path: path12,
|
|
2419
|
+
status: fileStatus
|
|
2420
|
+
});
|
|
2421
|
+
}
|
|
2422
|
+
}
|
|
2423
|
+
resolve(changes2);
|
|
2424
|
+
}
|
|
2425
|
+
);
|
|
2426
|
+
});
|
|
2427
|
+
} catch (error) {
|
|
2428
|
+
console.error("Failed to get git changes:", error);
|
|
2429
|
+
return [];
|
|
2430
|
+
}
|
|
2431
|
+
}
|
|
2432
|
+
async getGitRemoteStatus() {
|
|
2433
|
+
try {
|
|
2434
|
+
const { exec } = await import("child_process");
|
|
2435
|
+
return new Promise((resolve) => {
|
|
2436
|
+
exec(
|
|
2437
|
+
"git rev-list --left-right --count HEAD...@{u}",
|
|
2438
|
+
{ cwd: process.cwd() },
|
|
2439
|
+
(error, stdout, stderr) => {
|
|
2440
|
+
if (error) {
|
|
2441
|
+
resolve({ ahead: 0, behind: 0 });
|
|
2442
|
+
return;
|
|
2443
|
+
}
|
|
2444
|
+
const [behind, ahead] = stdout.trim().split(" ").map(Number);
|
|
2445
|
+
resolve({ ahead, behind });
|
|
2446
|
+
}
|
|
2447
|
+
);
|
|
2448
|
+
});
|
|
2449
|
+
} catch (error) {
|
|
2450
|
+
console.error("Failed to get remote status:", error);
|
|
2451
|
+
return { ahead: 0, behind: 0 };
|
|
2452
|
+
}
|
|
2453
|
+
}
|
|
2454
|
+
async getCurrentGitBranch() {
|
|
2455
|
+
try {
|
|
2456
|
+
const { exec } = await import("child_process");
|
|
2457
|
+
return new Promise((resolve) => {
|
|
2458
|
+
exec(
|
|
2459
|
+
"git branch --show-current",
|
|
2460
|
+
{ cwd: process.cwd() },
|
|
2461
|
+
(error, stdout, stderr) => {
|
|
2462
|
+
if (error) {
|
|
2463
|
+
console.error("Error getting current branch:", error);
|
|
2464
|
+
resolve("main");
|
|
2465
|
+
return;
|
|
2466
|
+
}
|
|
2467
|
+
resolve(stdout.trim() || "main");
|
|
2468
|
+
}
|
|
2469
|
+
);
|
|
2470
|
+
});
|
|
2471
|
+
} catch (error) {
|
|
2472
|
+
console.error("Failed to get current branch:", error);
|
|
2473
|
+
return "main";
|
|
2474
|
+
}
|
|
2475
|
+
}
|
|
2476
|
+
};
|
|
2477
|
+
}
|
|
2478
|
+
});
|
|
2479
|
+
|
|
2480
|
+
// src/PM/PM_WithProcesses.ts
|
|
2481
|
+
import fs9, { watch } from "fs";
|
|
2482
|
+
import path8 from "path";
|
|
2483
|
+
import puppeteer, { executablePath as executablePath2 } from "puppeteer-core";
|
|
2484
|
+
import ansiC3 from "ansi-colors";
|
|
2485
|
+
var fileHashes, changes, PM_WithProcesses;
|
|
2486
|
+
var init_PM_WithProcesses = __esm({
|
|
2487
|
+
async "src/PM/PM_WithProcesses.ts"() {
|
|
2488
|
+
"use strict";
|
|
2489
|
+
init_utils();
|
|
2490
|
+
init_utils2();
|
|
2491
|
+
await init_PM_WithGit();
|
|
2492
|
+
fileHashes = {};
|
|
2493
|
+
changes = {};
|
|
2494
|
+
PM_WithProcesses = class extends PM_WithGit {
|
|
2495
|
+
constructor(configs, name, mode2) {
|
|
2496
|
+
super(configs, name, mode2);
|
|
2497
|
+
this.logStreams = {};
|
|
2498
|
+
this.receiveFeaturesV2 = (reportDest, srcTest, platform) => {
|
|
2499
|
+
const featureDestination = path8.resolve(
|
|
2500
|
+
process.cwd(),
|
|
2501
|
+
"reports",
|
|
2502
|
+
"features",
|
|
2503
|
+
"strings",
|
|
2504
|
+
srcTest.split(".").slice(0, -1).join(".") + ".features.txt"
|
|
2505
|
+
);
|
|
2506
|
+
const testReportPath = `${reportDest}/tests.json`;
|
|
2507
|
+
if (!fs9.existsSync(testReportPath)) {
|
|
2508
|
+
console.error(`tests.json not found at: ${testReportPath}`);
|
|
2509
|
+
return;
|
|
2510
|
+
}
|
|
2511
|
+
const testReport = JSON.parse(fs9.readFileSync(testReportPath, "utf8"));
|
|
2512
|
+
if (testReport.tests) {
|
|
2513
|
+
testReport.tests.forEach((test) => {
|
|
2514
|
+
test.fullPath = path8.resolve(process.cwd(), srcTest);
|
|
2515
|
+
});
|
|
2516
|
+
}
|
|
2517
|
+
testReport.fullPath = path8.resolve(process.cwd(), srcTest);
|
|
2518
|
+
fs9.writeFileSync(testReportPath, JSON.stringify(testReport, null, 2));
|
|
2519
|
+
testReport.features.reduce(async (mm, featureStringKey) => {
|
|
2520
|
+
const accum = await mm;
|
|
2521
|
+
const isUrl = isValidUrl(featureStringKey);
|
|
2522
|
+
if (isUrl) {
|
|
2523
|
+
const u = new URL(featureStringKey);
|
|
2524
|
+
if (u.protocol === "file:") {
|
|
2525
|
+
const newPath = `${process.cwd()}/testeranto/features/internal/${path8.relative(
|
|
2526
|
+
process.cwd(),
|
|
2527
|
+
u.pathname
|
|
2528
|
+
)}`;
|
|
2529
|
+
accum.files.push(u.pathname);
|
|
2530
|
+
} else if (u.protocol === "http:" || u.protocol === "https:") {
|
|
2531
|
+
const newPath = `${process.cwd()}/testeranto/features/external/${u.hostname}${u.pathname}`;
|
|
2532
|
+
const body = await this.configs.featureIngestor(featureStringKey);
|
|
2533
|
+
writeFileAndCreateDir(newPath, body);
|
|
2534
|
+
accum.files.push(newPath);
|
|
2535
|
+
}
|
|
2536
|
+
} else {
|
|
2537
|
+
await fs9.promises.mkdir(path8.dirname(featureDestination), {
|
|
2538
|
+
recursive: true
|
|
2539
|
+
});
|
|
2540
|
+
accum.strings.push(featureStringKey);
|
|
2541
|
+
}
|
|
2542
|
+
return accum;
|
|
2543
|
+
}, Promise.resolve({ files: [], strings: [] })).then(({ files: files3, strings }) => {
|
|
2544
|
+
fs9.writeFileSync(
|
|
2545
|
+
`testeranto/reports/${this.name}/${srcTest.split(".").slice(0, -1).join(".")}/${platform}/featurePrompt.txt`,
|
|
2546
|
+
files3.map((f2) => {
|
|
2547
|
+
return `/read ${f2}`;
|
|
2548
|
+
}).join("\n")
|
|
2549
|
+
);
|
|
2550
|
+
});
|
|
2551
|
+
testReport.givens.forEach((g) => {
|
|
2552
|
+
if (g.failed === true) {
|
|
2553
|
+
this.summary[srcTest].failingFeatures[g.key] = g.features;
|
|
2554
|
+
}
|
|
2555
|
+
});
|
|
2556
|
+
this.writeBigBoard();
|
|
2557
|
+
};
|
|
2558
|
+
this.checkForShutdown = () => {
|
|
2559
|
+
this.checkQueue();
|
|
2560
|
+
console.log(
|
|
2561
|
+
ansiC3.inverse(
|
|
2562
|
+
`The following jobs are awaiting resources: ${JSON.stringify(
|
|
2563
|
+
this.queue
|
|
2564
|
+
)}`
|
|
2565
|
+
)
|
|
2566
|
+
);
|
|
2567
|
+
console.log(
|
|
2568
|
+
ansiC3.inverse(`The status of ports: ${JSON.stringify(this.ports)}`)
|
|
2569
|
+
);
|
|
2570
|
+
this.writeBigBoard();
|
|
2571
|
+
if (this.mode === "dev")
|
|
2572
|
+
return;
|
|
2573
|
+
let inflight = false;
|
|
2574
|
+
Object.keys(this.summary).forEach((k) => {
|
|
2575
|
+
if (this.summary[k].prompt === "?") {
|
|
2576
|
+
console.log(ansiC3.blue(ansiC3.inverse(`\u{1F555} prompt ${k}`)));
|
|
2577
|
+
inflight = true;
|
|
2578
|
+
}
|
|
2579
|
+
});
|
|
2580
|
+
Object.keys(this.summary).forEach((k) => {
|
|
2581
|
+
if (this.summary[k].runTimeErrors === "?") {
|
|
2582
|
+
console.log(ansiC3.blue(ansiC3.inverse(`\u{1F555} runTimeError ${k}`)));
|
|
2583
|
+
inflight = true;
|
|
2584
|
+
}
|
|
2585
|
+
});
|
|
2586
|
+
Object.keys(this.summary).forEach((k) => {
|
|
2587
|
+
if (this.summary[k].staticErrors === "?") {
|
|
2588
|
+
console.log(ansiC3.blue(ansiC3.inverse(`\u{1F555} staticErrors ${k}`)));
|
|
2589
|
+
inflight = true;
|
|
2590
|
+
}
|
|
2591
|
+
});
|
|
2592
|
+
Object.keys(this.summary).forEach((k) => {
|
|
2593
|
+
if (this.summary[k].typeErrors === "?") {
|
|
2594
|
+
console.log(ansiC3.blue(ansiC3.inverse(`\u{1F555} typeErrors ${k}`)));
|
|
2595
|
+
inflight = true;
|
|
2596
|
+
}
|
|
2597
|
+
});
|
|
2598
|
+
this.writeBigBoard();
|
|
2599
|
+
if (!inflight) {
|
|
2600
|
+
if (this.browser) {
|
|
2601
|
+
if (this.browser) {
|
|
2602
|
+
this.browser.disconnect().then(() => {
|
|
2603
|
+
console.log(
|
|
2604
|
+
ansiC3.inverse(`${this.name} has been tested. Goodbye.`)
|
|
2605
|
+
);
|
|
2606
|
+
process.exit();
|
|
2607
|
+
});
|
|
2608
|
+
}
|
|
2609
|
+
}
|
|
2610
|
+
}
|
|
2611
|
+
};
|
|
2612
|
+
this.launchers = {};
|
|
2613
|
+
this.ports = {};
|
|
2614
|
+
this.queue = [];
|
|
2615
|
+
this.configs.ports.forEach((element) => {
|
|
2616
|
+
this.ports[element] = "";
|
|
2617
|
+
});
|
|
2618
|
+
}
|
|
2619
|
+
async metafileOutputs(platform) {
|
|
2620
|
+
let metafilePath;
|
|
2621
|
+
if (platform === "python") {
|
|
2622
|
+
metafilePath = `./testeranto/metafiles/python/core.json`;
|
|
2623
|
+
} else {
|
|
2624
|
+
metafilePath = `./testeranto/metafiles/${platform}/${this.name}.json`;
|
|
2625
|
+
}
|
|
2626
|
+
if (!fs9.existsSync(metafilePath)) {
|
|
2627
|
+
if (platform === "python") {
|
|
2628
|
+
console.log(
|
|
2629
|
+
ansiC3.yellow(
|
|
2630
|
+
ansiC3.inverse(`Pitono metafile not found yet: ${metafilePath}`)
|
|
2631
|
+
)
|
|
2632
|
+
);
|
|
2633
|
+
}
|
|
2634
|
+
return;
|
|
2635
|
+
}
|
|
2636
|
+
let metafile;
|
|
2637
|
+
try {
|
|
2638
|
+
const fileContent = fs9.readFileSync(metafilePath).toString();
|
|
2639
|
+
const parsedData = JSON.parse(fileContent);
|
|
2640
|
+
if (platform === "python") {
|
|
2641
|
+
metafile = parsedData.metafile || parsedData;
|
|
2642
|
+
} else {
|
|
2643
|
+
metafile = parsedData.metafile;
|
|
2644
|
+
}
|
|
2645
|
+
if (!metafile) {
|
|
2646
|
+
console.log(
|
|
2647
|
+
ansiC3.yellow(ansiC3.inverse(`No metafile found in ${metafilePath}`))
|
|
2648
|
+
);
|
|
2649
|
+
return;
|
|
2650
|
+
}
|
|
2651
|
+
} catch (error) {
|
|
2652
|
+
console.error(`Error reading metafile at ${metafilePath}:`, error);
|
|
2653
|
+
return;
|
|
2654
|
+
}
|
|
2655
|
+
const outputs = metafile.outputs;
|
|
2656
|
+
if (!outputs || typeof outputs !== "object") {
|
|
2657
|
+
console.log(
|
|
2658
|
+
ansiC3.yellow(ansiC3.inverse(`No outputs found in metafile at ${metafilePath}`))
|
|
2659
|
+
);
|
|
2660
|
+
return;
|
|
2661
|
+
}
|
|
2662
|
+
Object.keys(outputs).forEach(async (k) => {
|
|
2663
|
+
const pattern = `testeranto/bundles/${platform}/${this.name}/${this.configs.src}`;
|
|
2664
|
+
if (!k.startsWith(pattern)) {
|
|
2665
|
+
return;
|
|
2666
|
+
}
|
|
2667
|
+
const output = outputs[k];
|
|
2668
|
+
if (!output || !output.inputs) {
|
|
2669
|
+
return;
|
|
2670
|
+
}
|
|
2671
|
+
const addableFiles = Object.keys(output.inputs).filter((i) => {
|
|
2672
|
+
if (!fs9.existsSync(i))
|
|
2673
|
+
return false;
|
|
2674
|
+
if (i.startsWith("node_modules"))
|
|
2675
|
+
return false;
|
|
2676
|
+
if (i.startsWith("./node_modules"))
|
|
2677
|
+
return false;
|
|
2678
|
+
return true;
|
|
2679
|
+
});
|
|
2680
|
+
const f2 = `${k.split(".").slice(0, -1).join(".")}/`;
|
|
2681
|
+
if (!fs9.existsSync(f2)) {
|
|
2682
|
+
fs9.mkdirSync(f2, { recursive: true });
|
|
2683
|
+
}
|
|
2684
|
+
const entrypoint = output.entryPoint;
|
|
2685
|
+
if (entrypoint) {
|
|
2686
|
+
const changeDigest = await filesHash(addableFiles);
|
|
2687
|
+
if (changeDigest === changes[entrypoint]) {
|
|
2688
|
+
} else {
|
|
2689
|
+
changes[entrypoint] = changeDigest;
|
|
2690
|
+
this.tscCheck({
|
|
2691
|
+
platform,
|
|
2692
|
+
addableFiles,
|
|
2693
|
+
entrypoint
|
|
2694
|
+
});
|
|
2695
|
+
this.eslintCheck(entrypoint, platform, addableFiles);
|
|
2696
|
+
this.makePrompt(entrypoint, addableFiles, platform);
|
|
2697
|
+
}
|
|
2698
|
+
}
|
|
2699
|
+
});
|
|
2700
|
+
}
|
|
2701
|
+
async start() {
|
|
2702
|
+
try {
|
|
2703
|
+
await this.startBuildProcesses();
|
|
2704
|
+
this.onBuildDone();
|
|
2705
|
+
} catch (error) {
|
|
2706
|
+
console.error("Build processes failed:", error);
|
|
2707
|
+
return;
|
|
2708
|
+
}
|
|
2709
|
+
this.mapping().forEach(async ([command, func]) => {
|
|
2710
|
+
globalThis[command] = func;
|
|
2711
|
+
});
|
|
2712
|
+
if (!fs9.existsSync(`testeranto/reports/${this.name}`)) {
|
|
2713
|
+
fs9.mkdirSync(`testeranto/reports/${this.name}`);
|
|
2714
|
+
}
|
|
2715
|
+
try {
|
|
2716
|
+
this.browser = await puppeteer.launch(puppeteerConfigs);
|
|
2717
|
+
} catch (e) {
|
|
2718
|
+
console.error(e);
|
|
2719
|
+
console.error(
|
|
2720
|
+
"could not start chrome via puppeter. Check this path: ",
|
|
2721
|
+
executablePath2
|
|
2722
|
+
);
|
|
2723
|
+
}
|
|
2724
|
+
const {
|
|
2725
|
+
nodeEntryPoints,
|
|
2726
|
+
webEntryPoints,
|
|
2727
|
+
pureEntryPoints,
|
|
2728
|
+
pythonEntryPoints,
|
|
2729
|
+
golangEntryPoints
|
|
2730
|
+
} = getRunnables(this.configs.tests, this.name);
|
|
2731
|
+
[
|
|
2732
|
+
[
|
|
2733
|
+
nodeEntryPoints,
|
|
2734
|
+
this.launchNode,
|
|
2735
|
+
"node",
|
|
2736
|
+
(w) => {
|
|
2737
|
+
this.nodeMetafileWatcher = w;
|
|
2738
|
+
}
|
|
2739
|
+
],
|
|
2740
|
+
[
|
|
2741
|
+
webEntryPoints,
|
|
2742
|
+
this.launchWeb,
|
|
2743
|
+
"web",
|
|
2744
|
+
(w) => {
|
|
2745
|
+
this.webMetafileWatcher = w;
|
|
2746
|
+
}
|
|
2747
|
+
],
|
|
2748
|
+
[
|
|
2749
|
+
pureEntryPoints,
|
|
2750
|
+
this.launchPure,
|
|
2751
|
+
"pure",
|
|
2752
|
+
(w) => {
|
|
2753
|
+
this.importMetafileWatcher = w;
|
|
2754
|
+
}
|
|
2755
|
+
],
|
|
2756
|
+
[
|
|
2757
|
+
pythonEntryPoints,
|
|
2758
|
+
this.launchPython,
|
|
2759
|
+
"python",
|
|
2760
|
+
(w) => {
|
|
2761
|
+
this.pitonoMetafileWatcher = w;
|
|
2762
|
+
}
|
|
2763
|
+
],
|
|
2764
|
+
[
|
|
2765
|
+
golangEntryPoints,
|
|
2766
|
+
this.launchGolang,
|
|
2767
|
+
"golang",
|
|
2768
|
+
(w) => {
|
|
2769
|
+
}
|
|
2770
|
+
]
|
|
2771
|
+
].forEach(
|
|
2772
|
+
async ([eps, launcher, runtime, watcher]) => {
|
|
2773
|
+
let metafile;
|
|
2774
|
+
if (runtime === "python") {
|
|
2775
|
+
metafile = `./testeranto/metafiles/python/core.json`;
|
|
2776
|
+
const metafileDir = path8.dirname(metafile);
|
|
2777
|
+
if (!fs9.existsSync(metafileDir)) {
|
|
2778
|
+
fs9.mkdirSync(metafileDir, { recursive: true });
|
|
2779
|
+
}
|
|
2780
|
+
} else {
|
|
2781
|
+
metafile = `./testeranto/metafiles/${runtime}/${this.name}.json`;
|
|
2782
|
+
}
|
|
2783
|
+
if (runtime !== "python") {
|
|
2784
|
+
await pollForFile(metafile);
|
|
2785
|
+
}
|
|
2786
|
+
Object.entries(eps).forEach(
|
|
2787
|
+
async ([inputFile, outputFile]) => {
|
|
2788
|
+
this.launchers[inputFile] = () => launcher(inputFile, outputFile);
|
|
2789
|
+
this.launchers[inputFile]();
|
|
2790
|
+
try {
|
|
2791
|
+
if (fs9.existsSync(outputFile)) {
|
|
2792
|
+
watch(outputFile, async (e, filename) => {
|
|
2793
|
+
const hash = await fileHash(outputFile);
|
|
2794
|
+
if (fileHashes[inputFile] !== hash) {
|
|
2795
|
+
fileHashes[inputFile] = hash;
|
|
2796
|
+
console.log(
|
|
2797
|
+
ansiC3.yellow(ansiC3.inverse(`< ${e} ${filename}`))
|
|
2798
|
+
);
|
|
2799
|
+
this.launchers[inputFile]();
|
|
2800
|
+
}
|
|
2801
|
+
});
|
|
2802
|
+
} else {
|
|
2803
|
+
console.log(
|
|
2804
|
+
ansiC3.yellow(
|
|
2805
|
+
ansiC3.inverse(
|
|
2806
|
+
`File not found, skipping watch: ${outputFile}`
|
|
2807
|
+
)
|
|
2808
|
+
)
|
|
2809
|
+
);
|
|
2810
|
+
}
|
|
2811
|
+
} catch (e) {
|
|
2812
|
+
console.error(e);
|
|
2813
|
+
}
|
|
2814
|
+
}
|
|
2815
|
+
);
|
|
2816
|
+
this.metafileOutputs(runtime);
|
|
2817
|
+
if (runtime === "python") {
|
|
2818
|
+
const checkFileExists = () => {
|
|
2819
|
+
if (fs9.existsSync(metafile)) {
|
|
2820
|
+
console.log(
|
|
2821
|
+
ansiC3.green(ansiC3.inverse(`Pitono metafile found: ${metafile}`))
|
|
2822
|
+
);
|
|
2823
|
+
watcher(
|
|
2824
|
+
watch(metafile, async (e, filename) => {
|
|
2825
|
+
console.log(
|
|
2826
|
+
ansiC3.yellow(
|
|
2827
|
+
ansiC3.inverse(`< ${e} ${filename} (${runtime})`)
|
|
2828
|
+
)
|
|
2829
|
+
);
|
|
2830
|
+
this.metafileOutputs(runtime);
|
|
2831
|
+
})
|
|
2832
|
+
);
|
|
2833
|
+
this.metafileOutputs(runtime);
|
|
2834
|
+
} else {
|
|
2835
|
+
setTimeout(checkFileExists, 1e3);
|
|
2836
|
+
}
|
|
2837
|
+
};
|
|
2838
|
+
checkFileExists();
|
|
2839
|
+
} else {
|
|
2840
|
+
if (fs9.existsSync(metafile)) {
|
|
2841
|
+
watcher(
|
|
2842
|
+
watch(metafile, async (e, filename) => {
|
|
2843
|
+
console.log(
|
|
2844
|
+
ansiC3.yellow(ansiC3.inverse(`< ${e} ${filename} (${runtime})`))
|
|
2845
|
+
);
|
|
2846
|
+
this.metafileOutputs(runtime);
|
|
2847
|
+
})
|
|
2848
|
+
);
|
|
2849
|
+
}
|
|
2850
|
+
}
|
|
2851
|
+
}
|
|
2852
|
+
);
|
|
2853
|
+
}
|
|
2854
|
+
async stop() {
|
|
2855
|
+
console.log(ansiC3.inverse("Testeranto-Run is shutting down gracefully..."));
|
|
2856
|
+
this.mode = "once";
|
|
2857
|
+
this.nodeMetafileWatcher.close();
|
|
2858
|
+
this.webMetafileWatcher.close();
|
|
2859
|
+
this.importMetafileWatcher.close();
|
|
2860
|
+
if (this.pitonoMetafileWatcher) {
|
|
2861
|
+
this.pitonoMetafileWatcher.close();
|
|
2862
|
+
}
|
|
2863
|
+
if (this.gitWatcher) {
|
|
2864
|
+
this.gitWatcher.close();
|
|
2865
|
+
}
|
|
2866
|
+
if (this.gitWatchTimeout) {
|
|
2867
|
+
clearTimeout(this.gitWatchTimeout);
|
|
2868
|
+
}
|
|
2869
|
+
Object.values(this.logStreams || {}).forEach((logs) => logs.closeAll());
|
|
2870
|
+
if (this.wss) {
|
|
2871
|
+
this.wss.close(() => {
|
|
2872
|
+
console.log("WebSocket server closed");
|
|
2873
|
+
});
|
|
2874
|
+
}
|
|
2875
|
+
this.clients.forEach((client) => {
|
|
2876
|
+
client.terminate();
|
|
2877
|
+
});
|
|
2878
|
+
this.clients.clear();
|
|
2879
|
+
if (this.httpServer) {
|
|
2880
|
+
this.httpServer.close(() => {
|
|
2881
|
+
console.log("HTTP server closed");
|
|
2882
|
+
});
|
|
2883
|
+
}
|
|
2884
|
+
this.checkForShutdown();
|
|
2885
|
+
}
|
|
2886
|
+
findIndexHtml() {
|
|
2887
|
+
const possiblePaths = [
|
|
2888
|
+
"dist/index.html",
|
|
2889
|
+
"testeranto/dist/index.html",
|
|
2890
|
+
"../dist/index.html",
|
|
2891
|
+
"./index.html"
|
|
2892
|
+
];
|
|
2893
|
+
for (const path12 of possiblePaths) {
|
|
2894
|
+
if (fs9.existsSync(path12)) {
|
|
2895
|
+
return path12;
|
|
2896
|
+
}
|
|
2897
|
+
}
|
|
2898
|
+
return null;
|
|
2899
|
+
}
|
|
2900
|
+
addToQueue(src, runtime) {
|
|
2901
|
+
this.queue.push(src);
|
|
2902
|
+
console.log(
|
|
2903
|
+
ansiC3.green(
|
|
2904
|
+
ansiC3.inverse(`Added ${src} (${runtime}) to the processing queue`)
|
|
2905
|
+
)
|
|
2906
|
+
);
|
|
2907
|
+
this.checkQueue();
|
|
2908
|
+
}
|
|
2909
|
+
checkQueue() {
|
|
2910
|
+
const x = this.queue.pop();
|
|
2911
|
+
if (!x) {
|
|
2912
|
+
ansiC3.inverse(`The following queue is empty`);
|
|
2913
|
+
return;
|
|
2914
|
+
}
|
|
2915
|
+
const test = this.configs.tests.find((t) => t[0] === x);
|
|
2916
|
+
if (!test)
|
|
2917
|
+
throw `test is undefined ${x}`;
|
|
2918
|
+
const runtime = test[1];
|
|
2919
|
+
const runnables = getRunnables(this.configs.tests, this.name);
|
|
2920
|
+
let dest;
|
|
2921
|
+
switch (runtime) {
|
|
2922
|
+
case "node":
|
|
2923
|
+
dest = runnables.nodeEntryPoints[x];
|
|
2924
|
+
if (dest) {
|
|
2925
|
+
this.launchNode(x, dest);
|
|
2926
|
+
} else {
|
|
2927
|
+
console.error(`No destination found for node test: ${x}`);
|
|
2928
|
+
}
|
|
2929
|
+
break;
|
|
2930
|
+
case "web":
|
|
2931
|
+
dest = runnables.webEntryPoints[x];
|
|
2932
|
+
if (dest) {
|
|
2933
|
+
this.launchWeb(x, dest);
|
|
2934
|
+
} else {
|
|
2935
|
+
console.error(`No destination found for web test: ${x}`);
|
|
2936
|
+
}
|
|
2937
|
+
break;
|
|
2938
|
+
case "pure":
|
|
2939
|
+
dest = runnables.pureEntryPoints[x];
|
|
2940
|
+
if (dest) {
|
|
2941
|
+
this.launchPure(x, dest);
|
|
2942
|
+
} else {
|
|
2943
|
+
console.error(`No destination found for pure test: ${x}`);
|
|
2944
|
+
}
|
|
2945
|
+
break;
|
|
2946
|
+
case "python":
|
|
2947
|
+
dest = runnables.pythonEntryPoints[x];
|
|
2948
|
+
if (dest) {
|
|
2949
|
+
this.launchPython(x, dest);
|
|
2950
|
+
} else {
|
|
2951
|
+
console.error(`No destination found for python test: ${x}`);
|
|
2952
|
+
}
|
|
2953
|
+
break;
|
|
2954
|
+
case "golang":
|
|
2955
|
+
dest = runnables.golangEntryPoints[x];
|
|
2956
|
+
if (dest) {
|
|
2957
|
+
this.launchGolang(x, dest);
|
|
2958
|
+
} else {
|
|
2959
|
+
console.error(`No destination found for golang test: ${x}`);
|
|
2960
|
+
}
|
|
2961
|
+
break;
|
|
2962
|
+
default:
|
|
2963
|
+
console.error(`Unknown runtime: ${runtime} for test ${x}`);
|
|
2964
|
+
break;
|
|
2965
|
+
}
|
|
2966
|
+
}
|
|
2967
|
+
onBuildDone() {
|
|
2968
|
+
console.log("Build processes completed");
|
|
2969
|
+
this.startGitWatcher();
|
|
2970
|
+
}
|
|
2971
|
+
};
|
|
2972
|
+
}
|
|
2973
|
+
});
|
|
2974
|
+
|
|
2975
|
+
// src/PM/main.ts
|
|
2976
|
+
var main_exports = {};
|
|
2977
|
+
__export(main_exports, {
|
|
2978
|
+
PM_Main: () => PM_Main
|
|
2979
|
+
});
|
|
2980
|
+
import { spawn as spawn2 } from "node:child_process";
|
|
2981
|
+
import ansiColors from "ansi-colors";
|
|
2982
|
+
import net from "net";
|
|
2983
|
+
import fs10 from "fs";
|
|
2984
|
+
import ansiC4 from "ansi-colors";
|
|
2985
|
+
var files2, screenshots2, PM_Main;
|
|
2986
|
+
var init_main = __esm({
|
|
2987
|
+
async "src/PM/main.ts"() {
|
|
2988
|
+
"use strict";
|
|
2989
|
+
init_utils();
|
|
2990
|
+
init_queue();
|
|
2991
|
+
init_utils2();
|
|
2992
|
+
await init_PM_WithProcesses();
|
|
2993
|
+
files2 = {};
|
|
2994
|
+
screenshots2 = {};
|
|
2995
|
+
PM_Main = class extends PM_WithProcesses {
|
|
2996
|
+
constructor() {
|
|
2997
|
+
super(...arguments);
|
|
2998
|
+
this.launchPure = async (src, dest) => {
|
|
2999
|
+
const processId = `pure-${src}-${Date.now()}`;
|
|
3000
|
+
const command = `pure test: ${src}`;
|
|
3001
|
+
const purePromise = (async () => {
|
|
3002
|
+
this.bddTestIsRunning(src);
|
|
3003
|
+
const reportDest = `testeranto/reports/${this.name}/${src.split(".").slice(0, -1).join(".")}/pure`;
|
|
3004
|
+
if (!fs10.existsSync(reportDest)) {
|
|
3005
|
+
fs10.mkdirSync(reportDest, { recursive: true });
|
|
3006
|
+
}
|
|
3007
|
+
const destFolder = dest.replace(".mjs", "");
|
|
3008
|
+
let argz = "";
|
|
3009
|
+
const testConfig = this.configs.tests.find((t) => {
|
|
3010
|
+
return t[0] === src;
|
|
3011
|
+
});
|
|
3012
|
+
if (!testConfig) {
|
|
3013
|
+
console.log(
|
|
3014
|
+
ansiC4.inverse("missing test config! Exiting ungracefully!")
|
|
3015
|
+
);
|
|
3016
|
+
process.exit(-1);
|
|
3017
|
+
}
|
|
3018
|
+
const testConfigResource = testConfig[2];
|
|
3019
|
+
const portsToUse = [];
|
|
3020
|
+
if (testConfigResource.ports === 0) {
|
|
3021
|
+
argz = JSON.stringify({
|
|
3022
|
+
scheduled: true,
|
|
3023
|
+
name: src,
|
|
3024
|
+
ports: portsToUse,
|
|
3025
|
+
fs: reportDest,
|
|
3026
|
+
browserWSEndpoint: this.browser.wsEndpoint()
|
|
3027
|
+
});
|
|
3028
|
+
} else if (testConfigResource.ports > 0) {
|
|
3029
|
+
const openPorts = Object.entries(this.ports).filter(
|
|
3030
|
+
([portnumber, status]) => status === ""
|
|
3031
|
+
);
|
|
3032
|
+
if (openPorts.length >= testConfigResource.ports) {
|
|
3033
|
+
for (let i = 0; i < testConfigResource.ports; i++) {
|
|
3034
|
+
portsToUse.push(openPorts[i][0]);
|
|
3035
|
+
this.ports[openPorts[i][0]] = src;
|
|
3036
|
+
}
|
|
3037
|
+
argz = JSON.stringify({
|
|
3038
|
+
scheduled: true,
|
|
3039
|
+
name: src,
|
|
3040
|
+
ports: portsToUse,
|
|
3041
|
+
fs: destFolder,
|
|
3042
|
+
browserWSEndpoint: this.browser.wsEndpoint()
|
|
3043
|
+
});
|
|
3044
|
+
} else {
|
|
3045
|
+
this.queue.push(src);
|
|
3046
|
+
return [Math.random(), argz];
|
|
3047
|
+
}
|
|
3048
|
+
} else {
|
|
3049
|
+
console.error("negative port makes no sense", src);
|
|
3050
|
+
process.exit(-1);
|
|
3051
|
+
}
|
|
3052
|
+
const builtfile = dest;
|
|
3053
|
+
const logs = createLogStreams(reportDest, "pure");
|
|
3054
|
+
try {
|
|
3055
|
+
await import(`${builtfile}?cacheBust=${Date.now()}`).then((module) => {
|
|
3056
|
+
return module.default.then((defaultModule) => {
|
|
3057
|
+
return defaultModule.receiveTestResourceConfig(argz).then(async (results) => {
|
|
3058
|
+
statusMessagePretty(results.fails, src, "pure");
|
|
3059
|
+
this.bddTestIsNowDone(src, results.fails);
|
|
3060
|
+
return results.fails;
|
|
3061
|
+
});
|
|
3062
|
+
}).catch((e2) => {
|
|
3063
|
+
console.log(
|
|
3064
|
+
ansiColors.red(
|
|
3065
|
+
`pure ! ${src} failed to execute. No "tests.json" file was generated. Check the logs for more info`
|
|
3066
|
+
)
|
|
3067
|
+
);
|
|
3068
|
+
logs.exit.write(e2.stack);
|
|
3069
|
+
logs.exit.write(-1);
|
|
3070
|
+
this.bddTestIsNowDone(src, -1);
|
|
3071
|
+
statusMessagePretty(-1, src, "pure");
|
|
3072
|
+
throw e2;
|
|
3073
|
+
});
|
|
3074
|
+
});
|
|
3075
|
+
} catch (e3) {
|
|
3076
|
+
logs.writeExitCode(-1, e3);
|
|
3077
|
+
console.log(
|
|
3078
|
+
ansiC4.red(
|
|
3079
|
+
ansiC4.inverse(
|
|
3080
|
+
`${src} 1 errored with: ${e3}. Check logs for more info`
|
|
3081
|
+
)
|
|
3082
|
+
)
|
|
3083
|
+
);
|
|
3084
|
+
logs.exit.write(e3.stack);
|
|
3085
|
+
logs.exit.write("-1");
|
|
3086
|
+
this.bddTestIsNowDone(src, -1);
|
|
3087
|
+
statusMessagePretty(-1, src, "pure");
|
|
3088
|
+
throw e3;
|
|
3089
|
+
} finally {
|
|
3090
|
+
for (let i = 0; i <= portsToUse.length; i++) {
|
|
3091
|
+
if (portsToUse[i]) {
|
|
3092
|
+
this.ports[portsToUse[i]] = "";
|
|
3093
|
+
}
|
|
3094
|
+
}
|
|
3095
|
+
}
|
|
3096
|
+
})();
|
|
3097
|
+
this.addPromiseProcess(
|
|
3098
|
+
processId,
|
|
3099
|
+
purePromise,
|
|
3100
|
+
command,
|
|
3101
|
+
"bdd-test",
|
|
3102
|
+
src,
|
|
3103
|
+
"pure"
|
|
3104
|
+
);
|
|
3105
|
+
};
|
|
3106
|
+
this.launchNode = async (src, dest) => {
|
|
3107
|
+
const processId = `node-${src}-${Date.now()}`;
|
|
3108
|
+
const command = `node test: ${src}`;
|
|
3109
|
+
const nodePromise = (async () => {
|
|
3110
|
+
this.bddTestIsRunning(src);
|
|
3111
|
+
const reportDest = `testeranto/reports/${this.name}/${src.split(".").slice(0, -1).join(".")}/node`;
|
|
3112
|
+
if (!fs10.existsSync(reportDest)) {
|
|
3113
|
+
fs10.mkdirSync(reportDest, { recursive: true });
|
|
3114
|
+
}
|
|
3115
|
+
let testResources = "";
|
|
3116
|
+
const testConfig = this.configs.tests.find((t) => {
|
|
3117
|
+
return t[0] === src;
|
|
3118
|
+
});
|
|
3119
|
+
if (!testConfig) {
|
|
3120
|
+
console.log(
|
|
3121
|
+
ansiC4.inverse(
|
|
3122
|
+
`missing test config! Exiting ungracefully for '${src}'`
|
|
3123
|
+
)
|
|
3124
|
+
);
|
|
3125
|
+
process.exit(-1);
|
|
3126
|
+
}
|
|
3127
|
+
const testConfigResource = testConfig[2];
|
|
3128
|
+
const portsToUse = [];
|
|
3129
|
+
if (testConfigResource.ports === 0) {
|
|
3130
|
+
const t = {
|
|
3131
|
+
name: src,
|
|
3132
|
+
ports: [],
|
|
3133
|
+
fs: reportDest,
|
|
3134
|
+
browserWSEndpoint: this.browser.wsEndpoint()
|
|
3135
|
+
};
|
|
3136
|
+
testResources = JSON.stringify(t);
|
|
3137
|
+
} else if (testConfigResource.ports > 0) {
|
|
3138
|
+
const openPorts = Object.entries(this.ports).filter(
|
|
3139
|
+
([portnumber, portopen]) => portopen === ""
|
|
3140
|
+
);
|
|
3141
|
+
if (openPorts.length >= testConfigResource.ports) {
|
|
3142
|
+
for (let i = 0; i < testConfigResource.ports; i++) {
|
|
3143
|
+
portsToUse.push(openPorts[i][0]);
|
|
3144
|
+
this.ports[openPorts[i][0]] = src;
|
|
3145
|
+
}
|
|
3146
|
+
testResources = JSON.stringify({
|
|
3147
|
+
scheduled: true,
|
|
3148
|
+
name: src,
|
|
3149
|
+
ports: portsToUse,
|
|
3150
|
+
fs: reportDest,
|
|
3151
|
+
browserWSEndpoint: this.browser.wsEndpoint()
|
|
3152
|
+
});
|
|
3153
|
+
} else {
|
|
3154
|
+
console.log(
|
|
3155
|
+
ansiC4.red(
|
|
3156
|
+
`node: cannot run ${src} because there are no open ports ATM. This job will be enqueued and run again run a port is available`
|
|
3157
|
+
)
|
|
3158
|
+
);
|
|
3159
|
+
this.queue.push(src);
|
|
3160
|
+
return [Math.random(), testResources];
|
|
3161
|
+
}
|
|
3162
|
+
} else {
|
|
3163
|
+
console.error("negative port makes no sense", src);
|
|
3164
|
+
process.exit(-1);
|
|
3165
|
+
}
|
|
3166
|
+
const builtfile = dest;
|
|
3167
|
+
let haltReturns = false;
|
|
3168
|
+
const ipcfile = "/tmp/tpipe_" + Math.random();
|
|
3169
|
+
const child = spawn2("node", [builtfile, testResources, ipcfile], {
|
|
3170
|
+
stdio: ["pipe", "pipe", "pipe", "ipc"]
|
|
3171
|
+
});
|
|
3172
|
+
let buffer = new Buffer("");
|
|
3173
|
+
const server = net.createServer((socket) => {
|
|
3174
|
+
const queue = new Queue();
|
|
3175
|
+
socket.on("data", (data) => {
|
|
3176
|
+
buffer = Buffer.concat([buffer, data]);
|
|
3177
|
+
for (let b = 0; b < buffer.length + 1; b++) {
|
|
3178
|
+
const c = buffer.slice(0, b);
|
|
3179
|
+
let d;
|
|
3180
|
+
try {
|
|
3181
|
+
d = JSON.parse(c.toString());
|
|
3182
|
+
queue.enqueue(d);
|
|
3183
|
+
buffer = buffer.slice(b, buffer.length + 1);
|
|
3184
|
+
b = 0;
|
|
3185
|
+
} catch (e) {
|
|
3186
|
+
}
|
|
3187
|
+
}
|
|
3188
|
+
while (queue.size() > 0) {
|
|
3189
|
+
const message = queue.dequeue();
|
|
3190
|
+
if (message) {
|
|
3191
|
+
this.mapping().forEach(async ([command2, func]) => {
|
|
3192
|
+
if (message[0] === command2) {
|
|
3193
|
+
const x = message.slice(1, -1);
|
|
3194
|
+
const r = await this[command2](...x);
|
|
3195
|
+
if (!haltReturns) {
|
|
3196
|
+
child.send(
|
|
3197
|
+
JSON.stringify({
|
|
3198
|
+
payload: r,
|
|
3199
|
+
key: message[message.length - 1]
|
|
3200
|
+
})
|
|
3201
|
+
);
|
|
3202
|
+
}
|
|
3203
|
+
}
|
|
3204
|
+
});
|
|
3205
|
+
}
|
|
3206
|
+
}
|
|
3207
|
+
});
|
|
3208
|
+
});
|
|
3209
|
+
const logs = createLogStreams(reportDest, "node");
|
|
3210
|
+
return new Promise((resolve, reject) => {
|
|
3211
|
+
server.listen(ipcfile, () => {
|
|
3212
|
+
child.stdout?.on("data", (data) => {
|
|
3213
|
+
logs.stdout?.write(data);
|
|
3214
|
+
});
|
|
3215
|
+
child.stderr?.on("data", (data) => {
|
|
3216
|
+
logs.stderr?.write(data);
|
|
3217
|
+
});
|
|
3218
|
+
child.on("close", (code) => {
|
|
3219
|
+
const exitCode = code === null ? -1 : code;
|
|
3220
|
+
if (exitCode < 0) {
|
|
3221
|
+
logs.writeExitCode(
|
|
3222
|
+
exitCode,
|
|
3223
|
+
new Error("Process crashed or was terminated")
|
|
3224
|
+
);
|
|
3225
|
+
} else {
|
|
3226
|
+
logs.writeExitCode(exitCode);
|
|
3227
|
+
}
|
|
3228
|
+
logs.closeAll();
|
|
3229
|
+
server.close();
|
|
3230
|
+
if (exitCode === 255) {
|
|
3231
|
+
console.log(
|
|
3232
|
+
ansiColors.red(
|
|
3233
|
+
`node ! ${src} failed to execute. No "tests.json" file was generated. Check ${reportDest}/stderr.log for more info`
|
|
3234
|
+
)
|
|
3235
|
+
);
|
|
3236
|
+
this.bddTestIsNowDone(src, -1);
|
|
3237
|
+
statusMessagePretty(-1, src, "node");
|
|
3238
|
+
reject(new Error(`Process exited with code ${exitCode}`));
|
|
3239
|
+
} else if (exitCode === 0) {
|
|
3240
|
+
this.bddTestIsNowDone(src, 0);
|
|
3241
|
+
statusMessagePretty(0, src, "node");
|
|
3242
|
+
resolve();
|
|
3243
|
+
} else {
|
|
3244
|
+
this.bddTestIsNowDone(src, exitCode);
|
|
3245
|
+
statusMessagePretty(exitCode, src, "node");
|
|
3246
|
+
reject(new Error(`Process exited with code ${exitCode}`));
|
|
3247
|
+
}
|
|
3248
|
+
haltReturns = true;
|
|
3249
|
+
});
|
|
3250
|
+
child.on("error", (e) => {
|
|
3251
|
+
console.log("error");
|
|
3252
|
+
haltReturns = true;
|
|
3253
|
+
console.log(
|
|
3254
|
+
ansiC4.red(
|
|
3255
|
+
ansiC4.inverse(
|
|
3256
|
+
`${src} errored with: ${e.name}. Check error logs for more info`
|
|
3257
|
+
)
|
|
3258
|
+
)
|
|
3259
|
+
);
|
|
3260
|
+
this.bddTestIsNowDone(src, -1);
|
|
3261
|
+
statusMessagePretty(-1, src, "node");
|
|
3262
|
+
reject(e);
|
|
3263
|
+
});
|
|
3264
|
+
});
|
|
3265
|
+
}).finally(() => {
|
|
3266
|
+
for (let i = 0; i <= portsToUse.length; i++) {
|
|
3267
|
+
if (portsToUse[i]) {
|
|
3268
|
+
this.ports[portsToUse[i]] = "";
|
|
3269
|
+
}
|
|
3270
|
+
}
|
|
3271
|
+
});
|
|
3272
|
+
})();
|
|
3273
|
+
this.addPromiseProcess(
|
|
3274
|
+
processId,
|
|
3275
|
+
nodePromise,
|
|
3276
|
+
command,
|
|
3277
|
+
"bdd-test",
|
|
3278
|
+
src,
|
|
3279
|
+
"node"
|
|
3280
|
+
);
|
|
3281
|
+
};
|
|
3282
|
+
this.launchWeb = async (src, dest) => {
|
|
3283
|
+
const processId = `web-${src}-${Date.now()}`;
|
|
3284
|
+
const command = `web test: ${src}`;
|
|
3285
|
+
const webPromise = (async () => {
|
|
3286
|
+
this.bddTestIsRunning(src);
|
|
3287
|
+
const reportDest = `testeranto/reports/${this.name}/${src.split(".").slice(0, -1).join(".")}/web`;
|
|
3288
|
+
if (!fs10.existsSync(reportDest)) {
|
|
3289
|
+
fs10.mkdirSync(reportDest, { recursive: true });
|
|
3290
|
+
}
|
|
3291
|
+
const destFolder = dest.replace(".mjs", "");
|
|
3292
|
+
const webArgz = JSON.stringify({
|
|
3293
|
+
name: src,
|
|
3294
|
+
ports: [].toString(),
|
|
3295
|
+
fs: reportDest,
|
|
3296
|
+
browserWSEndpoint: this.browser.wsEndpoint()
|
|
3297
|
+
});
|
|
3298
|
+
const d = `${dest}?cacheBust=${Date.now()}`;
|
|
3299
|
+
const logs = createLogStreams(reportDest, "web");
|
|
3300
|
+
return new Promise((resolve, reject) => {
|
|
3301
|
+
this.browser.newPage().then((page) => {
|
|
3302
|
+
page.on("console", (log) => {
|
|
3303
|
+
const msg = `${log.text()}
|
|
3304
|
+
`;
|
|
3305
|
+
switch (log.type()) {
|
|
3306
|
+
case "info":
|
|
3307
|
+
logs.info?.write(msg);
|
|
3308
|
+
break;
|
|
3309
|
+
case "warn":
|
|
3310
|
+
logs.warn?.write(msg);
|
|
3311
|
+
break;
|
|
3312
|
+
case "error":
|
|
3313
|
+
logs.error?.write(msg);
|
|
3314
|
+
break;
|
|
3315
|
+
case "debug":
|
|
3316
|
+
logs.debug?.write(msg);
|
|
3317
|
+
break;
|
|
3318
|
+
default:
|
|
3319
|
+
break;
|
|
3320
|
+
}
|
|
3321
|
+
});
|
|
3322
|
+
page.on("close", () => {
|
|
3323
|
+
logs.writeExitCode(0);
|
|
3324
|
+
logs.closeAll();
|
|
3325
|
+
});
|
|
3326
|
+
this.mapping().forEach(async ([command2, func]) => {
|
|
3327
|
+
if (command2 === "page") {
|
|
3328
|
+
page.exposeFunction(command2, (x) => {
|
|
3329
|
+
if (x) {
|
|
3330
|
+
return func(x);
|
|
3331
|
+
} else {
|
|
3332
|
+
return func(page.mainFrame()._id);
|
|
3333
|
+
}
|
|
3334
|
+
});
|
|
3335
|
+
} else {
|
|
3336
|
+
return page.exposeFunction(command2, func);
|
|
3337
|
+
}
|
|
3338
|
+
});
|
|
3339
|
+
return page;
|
|
3340
|
+
}).then(async (page) => {
|
|
3341
|
+
const close = () => {
|
|
3342
|
+
if (!files2[src]) {
|
|
3343
|
+
files2[src] = /* @__PURE__ */ new Set();
|
|
3344
|
+
}
|
|
3345
|
+
delete files2[src];
|
|
3346
|
+
Promise.all(screenshots2[src] || []).then(() => {
|
|
3347
|
+
delete screenshots2[src];
|
|
3348
|
+
page.close();
|
|
3349
|
+
});
|
|
3350
|
+
};
|
|
3351
|
+
page.on("pageerror", (err) => {
|
|
3352
|
+
logs.writeExitCode(-1, err);
|
|
3353
|
+
console.log(
|
|
3354
|
+
ansiColors.red(
|
|
3355
|
+
`web ! ${src} failed to execute No "tests.json" file was generated. Check ${reportDest}/error.log for more info`
|
|
3356
|
+
)
|
|
3357
|
+
);
|
|
3358
|
+
this.bddTestIsNowDone(src, -1);
|
|
3359
|
+
close();
|
|
3360
|
+
reject(err);
|
|
3361
|
+
});
|
|
3362
|
+
await page.goto(`file://${`${destFolder}.html`}`, {});
|
|
3363
|
+
await page.evaluate(webEvaluator(d, webArgz)).then(async ({ fails, failed, features }) => {
|
|
3364
|
+
statusMessagePretty(fails, src, "web");
|
|
3365
|
+
this.bddTestIsNowDone(src, fails);
|
|
3366
|
+
resolve();
|
|
3367
|
+
}).catch((e) => {
|
|
3368
|
+
console.log(ansiC4.red(ansiC4.inverse(e.stack)));
|
|
3369
|
+
console.log(
|
|
3370
|
+
ansiC4.red(
|
|
3371
|
+
ansiC4.inverse(
|
|
3372
|
+
`web ! ${src} failed to execute. No "tests.json" file was generated. Check logs for more info`
|
|
3373
|
+
)
|
|
3374
|
+
)
|
|
3375
|
+
);
|
|
3376
|
+
this.bddTestIsNowDone(src, -1);
|
|
3377
|
+
reject(e);
|
|
3378
|
+
}).finally(() => {
|
|
3379
|
+
close();
|
|
3380
|
+
});
|
|
3381
|
+
}).catch((error) => {
|
|
3382
|
+
reject(error);
|
|
3383
|
+
});
|
|
3384
|
+
});
|
|
3385
|
+
})();
|
|
3386
|
+
this.addPromiseProcess(
|
|
3387
|
+
processId,
|
|
3388
|
+
webPromise,
|
|
3389
|
+
command,
|
|
3390
|
+
"bdd-test",
|
|
3391
|
+
src,
|
|
3392
|
+
"web"
|
|
3393
|
+
);
|
|
3394
|
+
};
|
|
3395
|
+
this.launchPython = async (src, dest) => {
|
|
3396
|
+
const processId = `python-${src}-${Date.now()}`;
|
|
3397
|
+
const command = `python test: ${src}`;
|
|
3398
|
+
const pythonPromise = (async () => {
|
|
3399
|
+
this.bddTestIsRunning(src);
|
|
3400
|
+
const reportDest = `testeranto/reports/${this.name}/${src.split(".").slice(0, -1).join(".")}/python`;
|
|
3401
|
+
if (!fs10.existsSync(reportDest)) {
|
|
3402
|
+
fs10.mkdirSync(reportDest, { recursive: true });
|
|
3403
|
+
}
|
|
3404
|
+
let testResources = "";
|
|
3405
|
+
const testConfig = this.configs.tests.find((t) => t[0] === src);
|
|
3406
|
+
if (!testConfig) {
|
|
3407
|
+
console.log(
|
|
3408
|
+
ansiColors.inverse(
|
|
3409
|
+
`missing test config! Exiting ungracefully for '${src}'`
|
|
3410
|
+
)
|
|
3411
|
+
);
|
|
3412
|
+
process.exit(-1);
|
|
3413
|
+
}
|
|
3414
|
+
const testConfigResource = testConfig[2];
|
|
3415
|
+
const portsToUse = [];
|
|
3416
|
+
if (testConfigResource.ports === 0) {
|
|
3417
|
+
testResources = JSON.stringify({
|
|
3418
|
+
scheduled: true,
|
|
3419
|
+
name: src,
|
|
3420
|
+
ports: portsToUse,
|
|
3421
|
+
fs: reportDest,
|
|
3422
|
+
browserWSEndpoint: this.browser.wsEndpoint()
|
|
3423
|
+
});
|
|
3424
|
+
} else if (testConfigResource.ports > 0) {
|
|
3425
|
+
const openPorts = Object.entries(this.ports).filter(
|
|
3426
|
+
([, status]) => status === ""
|
|
3427
|
+
);
|
|
3428
|
+
if (openPorts.length >= testConfigResource.ports) {
|
|
3429
|
+
for (let i = 0; i < testConfigResource.ports; i++) {
|
|
3430
|
+
portsToUse.push(openPorts[i][0]);
|
|
3431
|
+
this.ports[openPorts[i][0]] = src;
|
|
3432
|
+
}
|
|
3433
|
+
testResources = JSON.stringify({
|
|
3434
|
+
scheduled: true,
|
|
3435
|
+
name: src,
|
|
3436
|
+
ports: portsToUse,
|
|
3437
|
+
fs: reportDest,
|
|
3438
|
+
browserWSEndpoint: this.browser.wsEndpoint()
|
|
3439
|
+
});
|
|
3440
|
+
} else {
|
|
3441
|
+
console.log(
|
|
3442
|
+
ansiColors.red(
|
|
3443
|
+
`python: cannot run ${src} because there are no open ports ATM. This job will be enqueued and run again when a port is available`
|
|
3444
|
+
)
|
|
3445
|
+
);
|
|
3446
|
+
this.queue.push(src);
|
|
3447
|
+
return;
|
|
3448
|
+
}
|
|
3449
|
+
} else {
|
|
3450
|
+
console.error("negative port makes no sense", src);
|
|
3451
|
+
process.exit(-1);
|
|
3452
|
+
}
|
|
3453
|
+
const logs = createLogStreams(reportDest, "python");
|
|
3454
|
+
const child = spawn2("python3", [src, testResources], {
|
|
3455
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
3456
|
+
});
|
|
3457
|
+
return new Promise((resolve, reject) => {
|
|
3458
|
+
child.stdout?.on("data", (data) => {
|
|
3459
|
+
logs.stdout?.write(data);
|
|
3460
|
+
});
|
|
3461
|
+
child.stderr?.on("data", (data) => {
|
|
3462
|
+
logs.stderr?.write(data);
|
|
3463
|
+
});
|
|
3464
|
+
child.on("close", (code) => {
|
|
3465
|
+
const exitCode = code === null ? -1 : code;
|
|
3466
|
+
if (exitCode < 0) {
|
|
3467
|
+
logs.writeExitCode(
|
|
3468
|
+
exitCode,
|
|
3469
|
+
new Error("Process crashed or was terminated")
|
|
3470
|
+
);
|
|
3471
|
+
} else {
|
|
3472
|
+
logs.writeExitCode(exitCode);
|
|
3473
|
+
}
|
|
3474
|
+
logs.closeAll();
|
|
3475
|
+
if (exitCode === 0) {
|
|
3476
|
+
this.bddTestIsNowDone(src, 0);
|
|
3477
|
+
statusMessagePretty(0, src, "python");
|
|
3478
|
+
resolve();
|
|
3479
|
+
} else {
|
|
3480
|
+
console.log(
|
|
3481
|
+
ansiColors.red(
|
|
3482
|
+
`python ! ${src} failed to execute. Check ${reportDest}/stderr.log for more info`
|
|
3483
|
+
)
|
|
3484
|
+
);
|
|
3485
|
+
this.bddTestIsNowDone(src, exitCode);
|
|
3486
|
+
statusMessagePretty(exitCode, src, "python");
|
|
3487
|
+
reject(new Error(`Process exited with code ${exitCode}`));
|
|
3488
|
+
}
|
|
3489
|
+
});
|
|
3490
|
+
child.on("error", (e) => {
|
|
3491
|
+
console.log(
|
|
3492
|
+
ansiColors.red(
|
|
3493
|
+
ansiColors.inverse(
|
|
3494
|
+
`python: ${src} errored with: ${e.name}. Check error logs for more info`
|
|
3495
|
+
)
|
|
3496
|
+
)
|
|
3497
|
+
);
|
|
3498
|
+
this.bddTestIsNowDone(src, -1);
|
|
3499
|
+
statusMessagePretty(-1, src, "python");
|
|
3500
|
+
reject(e);
|
|
3501
|
+
});
|
|
3502
|
+
}).finally(() => {
|
|
3503
|
+
portsToUse.forEach((port) => {
|
|
3504
|
+
this.ports[port] = "";
|
|
3505
|
+
});
|
|
3506
|
+
});
|
|
3507
|
+
})();
|
|
3508
|
+
this.addPromiseProcess(
|
|
3509
|
+
processId,
|
|
3510
|
+
pythonPromise,
|
|
3511
|
+
command,
|
|
3512
|
+
"bdd-test",
|
|
3513
|
+
src,
|
|
3514
|
+
"python"
|
|
3515
|
+
);
|
|
3516
|
+
};
|
|
3517
|
+
this.launchGolang = async (src, dest) => {
|
|
3518
|
+
const processId = `golang-${src}-${Date.now()}`;
|
|
3519
|
+
const command = `golang test: ${src}`;
|
|
3520
|
+
const golangPromise = (async () => {
|
|
3521
|
+
this.bddTestIsRunning(src);
|
|
3522
|
+
const reportDest = `testeranto/reports/${this.name}/${src.split(".").slice(0, -1).join(".")}/golang`;
|
|
3523
|
+
if (!fs10.existsSync(reportDest)) {
|
|
3524
|
+
fs10.mkdirSync(reportDest, { recursive: true });
|
|
3525
|
+
}
|
|
3526
|
+
let testResources = "";
|
|
3527
|
+
const testConfig = this.configs.tests.find((t) => t[0] === src);
|
|
3528
|
+
if (!testConfig) {
|
|
3529
|
+
console.log(
|
|
3530
|
+
ansiColors.inverse(
|
|
3531
|
+
`golang: missing test config! Exiting ungracefully for '${src}'`
|
|
3532
|
+
)
|
|
3533
|
+
);
|
|
3534
|
+
process.exit(-1);
|
|
3535
|
+
}
|
|
3536
|
+
const testConfigResource = testConfig[2];
|
|
3537
|
+
const portsToUse = [];
|
|
3538
|
+
if (testConfigResource.ports === 0) {
|
|
3539
|
+
testResources = JSON.stringify({
|
|
3540
|
+
scheduled: true,
|
|
3541
|
+
name: src,
|
|
3542
|
+
ports: portsToUse,
|
|
3543
|
+
fs: reportDest,
|
|
3544
|
+
browserWSEndpoint: this.browser.wsEndpoint()
|
|
3545
|
+
});
|
|
3546
|
+
} else if (testConfigResource.ports > 0) {
|
|
3547
|
+
const openPorts = Object.entries(this.ports).filter(
|
|
3548
|
+
([, status]) => status === ""
|
|
3549
|
+
);
|
|
3550
|
+
if (openPorts.length >= testConfigResource.ports) {
|
|
3551
|
+
for (let i = 0; i < testConfigResource.ports; i++) {
|
|
3552
|
+
portsToUse.push(openPorts[i][0]);
|
|
3553
|
+
this.ports[openPorts[i][0]] = src;
|
|
3554
|
+
}
|
|
3555
|
+
testResources = JSON.stringify({
|
|
3556
|
+
scheduled: true,
|
|
3557
|
+
name: src,
|
|
3558
|
+
ports: portsToUse,
|
|
3559
|
+
fs: reportDest,
|
|
3560
|
+
browserWSEndpoint: this.browser.wsEndpoint()
|
|
3561
|
+
});
|
|
3562
|
+
} else {
|
|
3563
|
+
console.log(
|
|
3564
|
+
ansiColors.red(
|
|
3565
|
+
`golang: cannot run ${src} because there are no open ports ATM. This job will be enqueued and run again when a port is available`
|
|
3566
|
+
)
|
|
3567
|
+
);
|
|
3568
|
+
this.queue.push(src);
|
|
3569
|
+
return;
|
|
3570
|
+
}
|
|
3571
|
+
} else {
|
|
3572
|
+
console.error("negative port makes no sense", src);
|
|
3573
|
+
process.exit(-1);
|
|
3574
|
+
}
|
|
3575
|
+
const buildDir = path.dirname(dest);
|
|
3576
|
+
const binaryName = path.basename(dest, ".go");
|
|
3577
|
+
const binaryPath = path.join(buildDir, binaryName);
|
|
3578
|
+
const logs = createLogStreams(reportDest, "golang");
|
|
3579
|
+
const compileProcess = spawn2("go", ["build", "-o", binaryPath, dest]);
|
|
3580
|
+
return new Promise((resolve, reject) => {
|
|
3581
|
+
compileProcess.stdout?.on("data", (data) => {
|
|
3582
|
+
logs.stdout?.write(data);
|
|
3583
|
+
});
|
|
3584
|
+
compileProcess.stderr?.on("data", (data) => {
|
|
3585
|
+
logs.stderr?.write(data);
|
|
3586
|
+
});
|
|
3587
|
+
compileProcess.on("close", (compileCode) => {
|
|
3588
|
+
if (compileCode !== 0) {
|
|
3589
|
+
console.log(
|
|
3590
|
+
ansiColors.red(
|
|
3591
|
+
`golang ! ${src} failed to compile. Check ${reportDest}/stderr.log for more info`
|
|
3592
|
+
)
|
|
3593
|
+
);
|
|
3594
|
+
this.bddTestIsNowDone(src, compileCode || -1);
|
|
3595
|
+
statusMessagePretty(compileCode || -1, src, "golang");
|
|
3596
|
+
reject(new Error(`Compilation failed with code ${compileCode}`));
|
|
3597
|
+
return;
|
|
3598
|
+
}
|
|
3599
|
+
const child = spawn2(binaryPath, [testResources], {
|
|
3600
|
+
stdio: ["pipe", "pipe", "pipe"]
|
|
3601
|
+
});
|
|
3602
|
+
child.stdout?.on("data", (data) => {
|
|
3603
|
+
logs.stdout?.write(data);
|
|
3604
|
+
});
|
|
3605
|
+
child.stderr?.on("data", (data) => {
|
|
3606
|
+
logs.stderr?.write(data);
|
|
3607
|
+
});
|
|
3608
|
+
child.on("close", (code) => {
|
|
3609
|
+
const exitCode = code === null ? -1 : code;
|
|
3610
|
+
if (exitCode < 0) {
|
|
3611
|
+
logs.writeExitCode(
|
|
3612
|
+
exitCode,
|
|
3613
|
+
new Error("Process crashed or was terminated")
|
|
3614
|
+
);
|
|
3615
|
+
} else {
|
|
3616
|
+
logs.writeExitCode(exitCode);
|
|
3617
|
+
}
|
|
3618
|
+
logs.closeAll();
|
|
3619
|
+
if (exitCode === 0) {
|
|
3620
|
+
this.bddTestIsNowDone(src, 0);
|
|
3621
|
+
statusMessagePretty(0, src, "golang");
|
|
3622
|
+
resolve();
|
|
3623
|
+
} else {
|
|
3624
|
+
console.log(
|
|
3625
|
+
ansiColors.red(
|
|
3626
|
+
`golang ! ${src} failed to execute. Check ${reportDest}/stderr.log for more info`
|
|
3627
|
+
)
|
|
3628
|
+
);
|
|
3629
|
+
this.bddTestIsNowDone(src, exitCode);
|
|
3630
|
+
statusMessagePretty(exitCode, src, "golang");
|
|
3631
|
+
reject(new Error(`Process exited with code ${exitCode}`));
|
|
3632
|
+
}
|
|
3633
|
+
});
|
|
3634
|
+
child.on("error", (e) => {
|
|
3635
|
+
console.log(
|
|
3636
|
+
ansiColors.red(
|
|
3637
|
+
ansiColors.inverse(
|
|
3638
|
+
`golang: ${src} errored with: ${e.name}. Check error logs for more info`
|
|
3639
|
+
)
|
|
3640
|
+
)
|
|
3641
|
+
);
|
|
3642
|
+
this.bddTestIsNowDone(src, -1);
|
|
3643
|
+
statusMessagePretty(-1, src, "golang");
|
|
3644
|
+
reject(e);
|
|
3645
|
+
});
|
|
3646
|
+
});
|
|
3647
|
+
compileProcess.on("error", (e) => {
|
|
3648
|
+
console.log(
|
|
3649
|
+
ansiColors.red(
|
|
3650
|
+
ansiColors.inverse(
|
|
3651
|
+
`golang: ${src} compilation errored with: ${e.name}. Check error logs for more info`
|
|
3652
|
+
)
|
|
3653
|
+
)
|
|
3654
|
+
);
|
|
3655
|
+
this.bddTestIsNowDone(src, -1);
|
|
3656
|
+
statusMessagePretty(-1, src, "golang");
|
|
3657
|
+
reject(e);
|
|
3658
|
+
});
|
|
3659
|
+
}).finally(() => {
|
|
3660
|
+
portsToUse.forEach((port) => {
|
|
3661
|
+
this.ports[port] = "";
|
|
3662
|
+
});
|
|
3663
|
+
});
|
|
3664
|
+
})();
|
|
3665
|
+
this.addPromiseProcess(
|
|
3666
|
+
processId,
|
|
3667
|
+
golangPromise,
|
|
3668
|
+
command,
|
|
3669
|
+
"bdd-test",
|
|
3670
|
+
src,
|
|
3671
|
+
"golang"
|
|
3672
|
+
);
|
|
3673
|
+
};
|
|
3674
|
+
}
|
|
3675
|
+
};
|
|
3676
|
+
}
|
|
3677
|
+
});
|
|
3678
|
+
|
|
3679
|
+
// src/utils/golingvuMetafile.ts
|
|
3680
|
+
var golingvuMetafile_exports = {};
|
|
3681
|
+
__export(golingvuMetafile_exports, {
|
|
3682
|
+
generateGolangMetafile: () => generateGolangMetafile,
|
|
3683
|
+
writeGolangMetafile: () => writeGolangMetafile
|
|
3684
|
+
});
|
|
3685
|
+
import fs11 from "fs";
|
|
3686
|
+
import path9 from "path";
|
|
3687
|
+
async function generateGolangMetafile(testName2, entryPoints) {
|
|
3688
|
+
const outputs = {};
|
|
3689
|
+
for (const entryPoint of entryPoints) {
|
|
3690
|
+
try {
|
|
3691
|
+
const entryDir = path9.dirname(entryPoint);
|
|
3692
|
+
const goFiles = fs11.readdirSync(entryDir).filter((file) => file.endsWith(".go")).map((file) => path9.join(entryDir, file));
|
|
3693
|
+
const inputs = {};
|
|
3694
|
+
let totalBytes = 0;
|
|
3695
|
+
for (const file of goFiles) {
|
|
3696
|
+
try {
|
|
3697
|
+
const stats = fs11.statSync(file);
|
|
3698
|
+
inputs[file] = { bytesInOutput: stats.size };
|
|
3699
|
+
totalBytes += stats.size;
|
|
3700
|
+
} catch {
|
|
3701
|
+
inputs[file] = { bytesInOutput: 0 };
|
|
3702
|
+
}
|
|
3703
|
+
}
|
|
3704
|
+
if (!inputs[entryPoint]) {
|
|
3705
|
+
try {
|
|
3706
|
+
const entryStats = fs11.statSync(entryPoint);
|
|
3707
|
+
inputs[entryPoint] = { bytesInOutput: entryStats.size };
|
|
3708
|
+
totalBytes += entryStats.size;
|
|
3709
|
+
} catch {
|
|
3710
|
+
inputs[entryPoint] = { bytesInOutput: 0 };
|
|
3711
|
+
}
|
|
3712
|
+
}
|
|
3713
|
+
const outputPath = `testeranto/bundles/golang/${testName2}/${entryPoint}`;
|
|
3714
|
+
outputs[outputPath] = {
|
|
3715
|
+
entryPoint,
|
|
3716
|
+
// Use the source file path, not the bundle path
|
|
3717
|
+
inputs,
|
|
3718
|
+
bytes: totalBytes
|
|
3719
|
+
};
|
|
3720
|
+
} catch (error) {
|
|
3721
|
+
console.error(`Error processing Go entry point ${entryPoint}:`, error);
|
|
3722
|
+
}
|
|
3723
|
+
}
|
|
3724
|
+
const allInputs = {};
|
|
3725
|
+
const allGoFiles = /* @__PURE__ */ new Set();
|
|
3726
|
+
for (const entryPoint of entryPoints) {
|
|
3727
|
+
try {
|
|
3728
|
+
const entryDir = path9.dirname(entryPoint);
|
|
3729
|
+
const goFiles = fs11.readdirSync(entryDir).filter((file) => file.endsWith(".go")).map((file) => path9.join(entryDir, file));
|
|
3730
|
+
goFiles.forEach((file) => allGoFiles.add(file));
|
|
3731
|
+
allGoFiles.add(entryPoint);
|
|
3732
|
+
} catch (error) {
|
|
3733
|
+
console.error(`Error processing Go entry point ${entryPoint} for source files:`, error);
|
|
3734
|
+
}
|
|
3735
|
+
}
|
|
3736
|
+
for (const filePath of Array.from(allGoFiles)) {
|
|
3737
|
+
try {
|
|
3738
|
+
const stats = fs11.statSync(filePath);
|
|
3739
|
+
allInputs[filePath] = {
|
|
3740
|
+
bytes: stats.size,
|
|
3741
|
+
imports: []
|
|
3742
|
+
// Go files don't have imports like JS
|
|
3743
|
+
};
|
|
3744
|
+
} catch {
|
|
3745
|
+
allInputs[filePath] = {
|
|
3746
|
+
bytes: 0,
|
|
3747
|
+
imports: []
|
|
3748
|
+
};
|
|
3749
|
+
}
|
|
3750
|
+
}
|
|
3751
|
+
const esbuildOutputs = {};
|
|
3752
|
+
for (const [outputPath, output] of Object.entries(outputs)) {
|
|
3753
|
+
esbuildOutputs[outputPath] = {
|
|
3754
|
+
bytes: output.bytes,
|
|
3755
|
+
inputs: output.inputs,
|
|
3756
|
+
entryPoint: output.entryPoint
|
|
3757
|
+
};
|
|
3758
|
+
}
|
|
3759
|
+
return {
|
|
3760
|
+
errors: [],
|
|
3761
|
+
warnings: [],
|
|
3762
|
+
metafile: {
|
|
3763
|
+
inputs: allInputs,
|
|
3764
|
+
outputs: esbuildOutputs
|
|
3765
|
+
}
|
|
3766
|
+
};
|
|
3767
|
+
}
|
|
3768
|
+
function writeGolangMetafile(testName2, metafile) {
|
|
3769
|
+
const metafileDir = path9.join(
|
|
3770
|
+
process.cwd(),
|
|
3771
|
+
"testeranto",
|
|
3772
|
+
"metafiles",
|
|
3773
|
+
"golang"
|
|
3774
|
+
);
|
|
3775
|
+
fs11.mkdirSync(metafileDir, { recursive: true });
|
|
3776
|
+
const metafilePath = path9.join(metafileDir, `${testName2}.json`);
|
|
3777
|
+
fs11.writeFileSync(metafilePath, JSON.stringify(metafile, null, 2));
|
|
3778
|
+
}
|
|
3779
|
+
var init_golingvuMetafile = __esm({
|
|
3780
|
+
"src/utils/golingvuMetafile.ts"() {
|
|
3781
|
+
"use strict";
|
|
3782
|
+
}
|
|
3783
|
+
});
|
|
3784
|
+
|
|
3785
|
+
// src/utils/pitonoMetafile.ts
|
|
3786
|
+
var pitonoMetafile_exports = {};
|
|
3787
|
+
__export(pitonoMetafile_exports, {
|
|
3788
|
+
generatePitonoMetafile: () => generatePitonoMetafile,
|
|
3789
|
+
writePitonoMetafile: () => writePitonoMetafile
|
|
3790
|
+
});
|
|
3791
|
+
import fs12 from "fs";
|
|
3792
|
+
import path10 from "path";
|
|
3793
|
+
import { execSync } from "child_process";
|
|
3794
|
+
async function generatePitonoMetafile(testName2, entryPoints) {
|
|
3795
|
+
return {
|
|
3796
|
+
testName: testName2,
|
|
3797
|
+
entryPoints,
|
|
3798
|
+
timestamp: Date.now()
|
|
3799
|
+
};
|
|
3800
|
+
}
|
|
3801
|
+
function writePitonoMetafile(testName2, metafile) {
|
|
3802
|
+
const metafilePath = path10.join(process.cwd(), "testeranto", "pitono", testName2, "metafile.json");
|
|
3803
|
+
const metafileDir = path10.dirname(metafilePath);
|
|
3804
|
+
if (!fs12.existsSync(metafileDir)) {
|
|
3805
|
+
fs12.mkdirSync(metafileDir, { recursive: true });
|
|
3806
|
+
}
|
|
3807
|
+
fs12.writeFileSync(metafilePath, JSON.stringify(metafile, null, 2));
|
|
3808
|
+
console.log(`Pitono metafile written to: ${metafilePath}`);
|
|
3809
|
+
try {
|
|
3810
|
+
const command = `pitono-core-generator ${testName2} ${metafile.entryPoints.join(" ")}`;
|
|
3811
|
+
execSync(command, { stdio: "inherit" });
|
|
3812
|
+
console.log(`Pitono core.json generated successfully for ${testName2}`);
|
|
3813
|
+
} catch (error) {
|
|
3814
|
+
console.error(`Failed to generate Pitono core.json with installed command: ${error}`);
|
|
3815
|
+
try {
|
|
3816
|
+
const pythonCommand = `python ${process.cwd()}/pitono/core_generator.py ${testName2} ${metafile.entryPoints.join(" ")}`;
|
|
3817
|
+
execSync(pythonCommand, { stdio: "inherit" });
|
|
3818
|
+
console.log(`Pitono core.json generated successfully using direct Python execution`);
|
|
3819
|
+
} catch (fallbackError) {
|
|
3820
|
+
console.error(`Direct Python execution also failed: ${fallbackError}`);
|
|
3821
|
+
try {
|
|
3822
|
+
const coreData = {
|
|
3823
|
+
testName: testName2,
|
|
3824
|
+
entryPoints: metafile.entryPoints,
|
|
3825
|
+
outputs: {},
|
|
3826
|
+
metafile: {
|
|
3827
|
+
inputs: {},
|
|
3828
|
+
outputs: {}
|
|
3829
|
+
},
|
|
3830
|
+
timestamp: Date.now(),
|
|
3831
|
+
runtime: "pitono"
|
|
3832
|
+
};
|
|
3833
|
+
const coreFilePath = path10.join(process.cwd(), "testeranto", "pitono", testName2, "core.json");
|
|
3834
|
+
fs12.writeFileSync(coreFilePath, JSON.stringify(coreData, null, 2));
|
|
3835
|
+
console.log(`Pitono core.json created manually as fallback`);
|
|
3836
|
+
} catch (manualError) {
|
|
3837
|
+
console.error(`Even manual creation failed: ${manualError}`);
|
|
3838
|
+
}
|
|
3839
|
+
}
|
|
3840
|
+
}
|
|
3841
|
+
}
|
|
3842
|
+
var init_pitonoMetafile = __esm({
|
|
3843
|
+
"src/utils/pitonoMetafile.ts"() {
|
|
3844
|
+
"use strict";
|
|
3845
|
+
}
|
|
3846
|
+
});
|
|
3847
|
+
|
|
3848
|
+
// src/testeranto.ts
|
|
3849
|
+
init_utils();
|
|
3850
|
+
import ansiC5 from "ansi-colors";
|
|
3851
|
+
import fs13 from "fs";
|
|
3852
|
+
import path11 from "path";
|
|
3853
|
+
import readline from "readline";
|
|
3854
|
+
|
|
3855
|
+
// src/utils/buildTemplates.ts
|
|
3856
|
+
var getBaseHtml = (title) => `
|
|
3857
|
+
<!DOCTYPE html>
|
|
3858
|
+
<html lang="en">
|
|
3859
|
+
<head>
|
|
3860
|
+
<meta name="description" content="Webpage description goes here" />
|
|
3861
|
+
<meta charset="utf-8" />
|
|
3862
|
+
<title>${title} - testeranto</title>
|
|
3863
|
+
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
|
3864
|
+
<meta name="author" content="" />
|
|
3865
|
+
|
|
3866
|
+
<script>
|
|
3867
|
+
function initApp() {
|
|
3868
|
+
if (window.React && window.ReactDOM && window.App) {
|
|
3869
|
+
const root = ReactDOM.createRoot(document.getElementById('root'));
|
|
3870
|
+
root.render(React.createElement(App));
|
|
3871
|
+
} else {
|
|
3872
|
+
setTimeout(initApp, 100);
|
|
3873
|
+
}
|
|
3874
|
+
}
|
|
3875
|
+
window.addEventListener('DOMContentLoaded', initApp);
|
|
3876
|
+
</script>
|
|
3877
|
+
`;
|
|
3878
|
+
var AppHtml = () => `
|
|
3879
|
+
${getBaseHtml("Testeranto")}
|
|
3880
|
+
|
|
3881
|
+
<link rel="stylesheet" href="App.css" />
|
|
3882
|
+
<script src="App.js"></script>
|
|
3883
|
+
</head>
|
|
3884
|
+
<body>
|
|
3885
|
+
<div id="root"></div>
|
|
3886
|
+
</body>
|
|
3887
|
+
</html>
|
|
3888
|
+
`;
|
|
3889
|
+
|
|
3890
|
+
// src/web.html.ts
|
|
3891
|
+
var web_html_default = (jsfilePath, htmlFilePath, cssfilePath) => `
|
|
3892
|
+
<!DOCTYPE html>
|
|
3893
|
+
<html lang="en">
|
|
3894
|
+
|
|
3895
|
+
<head>
|
|
3896
|
+
<script type="module" src="${jsfilePath}"></script>
|
|
3897
|
+
<link rel="stylesheet" href="${cssfilePath}">
|
|
3898
|
+
</head>
|
|
3899
|
+
|
|
3900
|
+
<body>
|
|
3901
|
+
<div id="root">
|
|
3902
|
+
</div>
|
|
3903
|
+
</body>
|
|
3904
|
+
|
|
3905
|
+
</html>
|
|
3906
|
+
`;
|
|
3907
|
+
|
|
3908
|
+
// src/testeranto.ts
|
|
3909
|
+
if (!process.env.GITHUB_CLIENT_ID) {
|
|
3910
|
+
console.error(`env var "GITHUB_CLIENT_ID" needs to be set!`);
|
|
3911
|
+
process.exit(-1);
|
|
3912
|
+
}
|
|
3913
|
+
if (!process.env.GITHUB_CLIENT_SECRET) {
|
|
3914
|
+
console.error(`env var "GITHUB_CLIENT_SECRET" needs to be set!`);
|
|
3915
|
+
process.exit(-1);
|
|
3916
|
+
}
|
|
3917
|
+
readline.emitKeypressEvents(process.stdin);
|
|
3918
|
+
if (process.stdin.isTTY)
|
|
3919
|
+
process.stdin.setRawMode(true);
|
|
3920
|
+
var testName = process.argv[2];
|
|
3921
|
+
var mode = process.argv[3];
|
|
3922
|
+
if (mode !== "once" && mode !== "dev") {
|
|
3923
|
+
console.error(`The 3rd argument should be 'dev' or 'once', not '${mode}'.`);
|
|
3924
|
+
process.exit(-1);
|
|
3925
|
+
}
|
|
3926
|
+
var f = process.cwd() + "/testeranto.config.ts";
|
|
3927
|
+
console.log("config file:", f);
|
|
3928
|
+
import(f).then(async (module) => {
|
|
3929
|
+
const pckge = (await import(`${process.cwd()}/package.json`)).default;
|
|
3930
|
+
const bigConfig = module.default;
|
|
3931
|
+
const project = bigConfig.projects[testName];
|
|
3932
|
+
if (!project) {
|
|
3933
|
+
console.error("no project found for", testName, "in testeranto.config.ts");
|
|
3934
|
+
process.exit(-1);
|
|
3935
|
+
}
|
|
3936
|
+
try {
|
|
3937
|
+
fs13.writeFileSync(
|
|
3938
|
+
`${process.cwd()}/testeranto/projects.json`,
|
|
3939
|
+
JSON.stringify(Object.keys(bigConfig.projects), null, 2)
|
|
3940
|
+
);
|
|
3941
|
+
} catch (e) {
|
|
3942
|
+
console.error("there was a problem");
|
|
3943
|
+
console.error(e);
|
|
3944
|
+
}
|
|
3945
|
+
const rawConfig = bigConfig.projects[testName];
|
|
3946
|
+
if (!rawConfig) {
|
|
3947
|
+
console.error(`Project "${testName}" does not exist in the configuration.`);
|
|
3948
|
+
console.error("Available projects:", Object.keys(bigConfig.projects));
|
|
3949
|
+
process.exit(-1);
|
|
3950
|
+
}
|
|
3951
|
+
if (!rawConfig.tests) {
|
|
3952
|
+
console.error(testName, "appears to have no tests: ", f);
|
|
3953
|
+
console.error(`here is the config:`);
|
|
3954
|
+
console.log(JSON.stringify(rawConfig));
|
|
3955
|
+
process.exit(-1);
|
|
3956
|
+
}
|
|
3957
|
+
const config = {
|
|
3958
|
+
...rawConfig,
|
|
3959
|
+
buildDir: process.cwd() + "/testeranto/bundles/" + testName
|
|
3960
|
+
};
|
|
3961
|
+
console.log(ansiC5.inverse("Press 'q' to initiate a graceful shutdown."));
|
|
3962
|
+
console.log(ansiC5.inverse("Press 'x' to quit forcefully."));
|
|
3963
|
+
process.stdin.on("keypress", (str, key) => {
|
|
3964
|
+
if (key.name === "x") {
|
|
3965
|
+
console.log(ansiC5.inverse("Shutting down forcefully..."));
|
|
3966
|
+
process.exit(-1);
|
|
3967
|
+
}
|
|
3968
|
+
});
|
|
3969
|
+
let pm = null;
|
|
3970
|
+
const { PM_Main: PM_Main2 } = await init_main().then(() => main_exports);
|
|
3971
|
+
pm = new PM_Main2(config, testName, mode);
|
|
3972
|
+
await pm.start();
|
|
3973
|
+
fs13.writeFileSync(`${process.cwd()}/testeranto/projects.html`, AppHtml());
|
|
3974
|
+
Object.keys(bigConfig.projects).forEach((projectName) => {
|
|
3975
|
+
console.log(`testeranto/reports/${projectName}`);
|
|
3976
|
+
if (!fs13.existsSync(`testeranto/reports/${projectName}`)) {
|
|
3977
|
+
fs13.mkdirSync(`testeranto/reports/${projectName}`);
|
|
3978
|
+
}
|
|
3979
|
+
fs13.writeFileSync(
|
|
3980
|
+
`testeranto/reports/${projectName}/config.json`,
|
|
3981
|
+
JSON.stringify(config, null, 2)
|
|
3982
|
+
);
|
|
3983
|
+
});
|
|
3984
|
+
const getSecondaryEndpointsPoints = (runtime) => {
|
|
3985
|
+
const meta = (ts2, st) => {
|
|
3986
|
+
ts2.forEach((t) => {
|
|
3987
|
+
if (t[1] === runtime) {
|
|
3988
|
+
st.add(t[0]);
|
|
3989
|
+
}
|
|
3990
|
+
if (Array.isArray(t[3])) {
|
|
3991
|
+
meta(t[3], st);
|
|
3992
|
+
}
|
|
3993
|
+
});
|
|
3994
|
+
return st;
|
|
3995
|
+
};
|
|
3996
|
+
return Array.from(meta(config.tests, /* @__PURE__ */ new Set()));
|
|
3997
|
+
};
|
|
3998
|
+
[...getSecondaryEndpointsPoints("python")].forEach(async (sourceFilePath) => {
|
|
3999
|
+
console.log(`Pitono test found: ${sourceFilePath}`);
|
|
4000
|
+
});
|
|
4001
|
+
const golangTests = config.tests.filter((test) => test[1] === "golang");
|
|
4002
|
+
const hasGolangTests = golangTests.length > 0;
|
|
4003
|
+
if (hasGolangTests) {
|
|
4004
|
+
const { generateGolangMetafile: generateGolangMetafile2, writeGolangMetafile: writeGolangMetafile2 } = await Promise.resolve().then(() => (init_golingvuMetafile(), golingvuMetafile_exports));
|
|
4005
|
+
const golangEntryPoints = golangTests.map((test) => test[0]);
|
|
4006
|
+
const metafile = await generateGolangMetafile2(testName, golangEntryPoints);
|
|
4007
|
+
writeGolangMetafile2(testName, metafile);
|
|
4008
|
+
}
|
|
4009
|
+
const pitonoTests = config.tests.filter((test) => test[1] === "python");
|
|
4010
|
+
const hasPitonoTests = pitonoTests.length > 0;
|
|
4011
|
+
if (hasPitonoTests) {
|
|
4012
|
+
const { generatePitonoMetafile: generatePitonoMetafile2 } = await Promise.resolve().then(() => (init_pitonoMetafile(), pitonoMetafile_exports));
|
|
4013
|
+
const pitonoEntryPoints = pitonoTests.map((test) => test[0]);
|
|
4014
|
+
const metafile = await generatePitonoMetafile2(testName, pitonoEntryPoints);
|
|
4015
|
+
const pitonoMetafilePath = `${process.cwd()}/testeranto/metafiles/python`;
|
|
4016
|
+
await fs13.promises.mkdir(pitonoMetafilePath, { recursive: true });
|
|
4017
|
+
fs13.writeFileSync(
|
|
4018
|
+
`${pitonoMetafilePath}/core.json`,
|
|
4019
|
+
JSON.stringify(metafile, null, 2)
|
|
4020
|
+
);
|
|
4021
|
+
console.log(
|
|
4022
|
+
ansiC5.green(
|
|
4023
|
+
ansiC5.inverse(`Python metafile written to: ${pitonoMetafilePath}/core.json`)
|
|
4024
|
+
)
|
|
4025
|
+
);
|
|
4026
|
+
pitonoEntryPoints.forEach((entryPoint) => {
|
|
4027
|
+
if (pm) {
|
|
4028
|
+
pm.addToQueue(entryPoint, "python");
|
|
4029
|
+
}
|
|
4030
|
+
});
|
|
4031
|
+
}
|
|
4032
|
+
Promise.resolve(
|
|
4033
|
+
Promise.all(
|
|
4034
|
+
[...getSecondaryEndpointsPoints("web")].map(async (sourceFilePath) => {
|
|
4035
|
+
const sourceFileSplit = sourceFilePath.split("/");
|
|
4036
|
+
const sourceDir = sourceFileSplit.slice(0, -1);
|
|
4037
|
+
const sourceFileName = sourceFileSplit[sourceFileSplit.length - 1];
|
|
4038
|
+
const sourceFileNameMinusJs = sourceFileName.split(".").slice(0, -1).join(".");
|
|
4039
|
+
const htmlFilePath = path11.normalize(
|
|
4040
|
+
`${process.cwd()}/testeranto/bundles/web/${testName}/${sourceDir.join(
|
|
4041
|
+
"/"
|
|
4042
|
+
)}/${sourceFileNameMinusJs}.html`
|
|
4043
|
+
);
|
|
4044
|
+
const jsfilePath = `./${sourceFileNameMinusJs}.mjs`;
|
|
4045
|
+
const cssFilePath = `./${sourceFileNameMinusJs}.css`;
|
|
4046
|
+
return fs13.promises.mkdir(path11.dirname(htmlFilePath), { recursive: true }).then(
|
|
4047
|
+
(x2) => fs13.writeFileSync(
|
|
4048
|
+
htmlFilePath,
|
|
4049
|
+
web_html_default(jsfilePath, htmlFilePath, cssFilePath)
|
|
4050
|
+
)
|
|
4051
|
+
);
|
|
4052
|
+
})
|
|
4053
|
+
)
|
|
4054
|
+
);
|
|
4055
|
+
const {
|
|
4056
|
+
nodeEntryPoints,
|
|
4057
|
+
nodeEntryPointSidecars,
|
|
4058
|
+
webEntryPoints,
|
|
4059
|
+
webEntryPointSidecars,
|
|
4060
|
+
pureEntryPoints,
|
|
4061
|
+
pureEntryPointSidecars,
|
|
4062
|
+
pythonEntryPoints,
|
|
4063
|
+
pythonEntryPointSidecars
|
|
4064
|
+
} = getRunnables(config.tests, testName);
|
|
4065
|
+
const x = [
|
|
4066
|
+
["pure", Object.keys(pureEntryPoints)],
|
|
4067
|
+
["node", Object.keys(nodeEntryPoints)],
|
|
4068
|
+
["web", Object.keys(webEntryPoints)],
|
|
4069
|
+
["python", Object.keys(pythonEntryPoints)]
|
|
4070
|
+
];
|
|
4071
|
+
x.forEach(async ([runtime, keys]) => {
|
|
4072
|
+
keys.forEach(async (k) => {
|
|
4073
|
+
const folder = `testeranto/reports/${testName}/${k.split(".").slice(0, -1).join(".")}/${runtime}`;
|
|
4074
|
+
await fs13.mkdirSync(folder, { recursive: true });
|
|
4075
|
+
});
|
|
4076
|
+
});
|
|
4077
|
+
[
|
|
4078
|
+
[pureEntryPoints, pureEntryPointSidecars, "pure"],
|
|
4079
|
+
[webEntryPoints, webEntryPointSidecars, "web"],
|
|
4080
|
+
[nodeEntryPoints, nodeEntryPointSidecars, "node"],
|
|
4081
|
+
[pythonEntryPoints, pythonEntryPointSidecars, "python"]
|
|
4082
|
+
].forEach(
|
|
4083
|
+
([eps, eps2, runtime]) => {
|
|
4084
|
+
[...Object.keys(eps), ...Object.keys(eps2)].forEach((ep) => {
|
|
4085
|
+
const fp = path11.resolve(
|
|
4086
|
+
`testeranto`,
|
|
4087
|
+
`reports`,
|
|
4088
|
+
testName,
|
|
4089
|
+
ep.split(".").slice(0, -1).join("."),
|
|
4090
|
+
runtime
|
|
4091
|
+
);
|
|
4092
|
+
fs13.mkdirSync(fp, { recursive: true });
|
|
4093
|
+
});
|
|
4094
|
+
}
|
|
4095
|
+
);
|
|
4096
|
+
process.stdin.on("keypress", (str, key) => {
|
|
4097
|
+
if (key.name === "q") {
|
|
4098
|
+
console.log("Testeranto is shutting down gracefully...");
|
|
4099
|
+
if (pm) {
|
|
4100
|
+
pm.stop();
|
|
4101
|
+
} else {
|
|
4102
|
+
process.exit();
|
|
4103
|
+
}
|
|
4104
|
+
}
|
|
4105
|
+
});
|
|
4106
|
+
});
|