@skyramp/mcp 0.3.2-rc.pom-4 → 0.3.3
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/build/adapters/jestAdapter.d.ts +14 -0
- package/build/adapters/jestAdapter.js +113 -0
- package/build/adapters/mochaAdapter.d.ts +13 -0
- package/build/adapters/mochaAdapter.js +87 -0
- package/build/adapters/playwrightAdapter.d.ts +17 -0
- package/build/adapters/playwrightAdapter.js +182 -0
- package/build/adapters/pytestAdapter.d.ts +15 -0
- package/build/adapters/pytestAdapter.js +108 -0
- package/build/commands/commandLibrary.d.ts +1 -0
- package/build/commands/commandLibrary.js +19 -13
- package/build/commands/localDevTestChangesCommand.d.ts +15 -0
- package/build/commands/localDevTestChangesCommand.js +201 -0
- package/build/index.js +129 -8
- package/build/playwright/PlaywrightTraceService.d.ts +8 -0
- package/build/playwright/PlaywrightTraceService.js +1 -0
- package/build/prompts/code-reuse.js +3 -0
- package/build/prompts/enhance-assertions/sharedAssertionRules.d.ts +1 -0
- package/build/prompts/enhance-assertions/sharedAssertionRules.js +17 -0
- package/build/prompts/initialize-workspace/initializeWorkspacePrompt.js +11 -9
- package/build/prompts/local-dev/local-dev-plan.d.ts +35 -0
- package/build/prompts/local-dev/local-dev-plan.js +429 -0
- package/build/prompts/local-dev/local-dev-prompts.d.ts +4 -0
- package/build/prompts/local-dev/local-dev-prompts.js +190 -0
- package/build/prompts/pom-aware-code-reuse.js +17 -8
- package/build/prompts/prompt-utils.d.ts +8 -0
- package/build/prompts/prompt-utils.js +33 -0
- package/build/prompts/sut-setup/modes/adaptWorkflowPrompt.js +70 -7
- package/build/prompts/sut-setup/modes/dockerComposePrompt.js +1 -1
- package/build/prompts/sut-setup/shared.js +19 -17
- package/build/prompts/test-maintenance/drift-analysis-prompt.d.ts +10 -1
- package/build/prompts/test-maintenance/drift-analysis-prompt.js +54 -1
- package/build/prompts/test-recommendation/analysisOutputPrompt.js +21 -29
- package/build/prompts/test-recommendation/scopeAssessment.d.ts +5 -2
- package/build/prompts/test-recommendation/scopeAssessment.js +78 -6
- package/build/prompts/test-recommendation/test-recommendation-prompt.js +41 -4
- package/build/prompts/testbot/testbot-prompts.d.ts +2 -17
- package/build/prompts/testbot/testbot-prompts.js +63 -60
- package/build/recommendation/planRanker.d.ts +15 -2
- package/build/recommendation/planRanker.js +76 -5
- package/build/resources/testbotResource.js +23 -5
- package/build/services/AnalyticsService.d.ts +1 -1
- package/build/services/TestExecutionService.d.ts +15 -9
- package/build/services/TestExecutionService.js +56 -28
- package/build/services/TestGenerationService.d.ts +2 -2
- package/build/services/TestGenerationService.js +39 -21
- package/build/services/containerEnv.js +27 -1
- package/build/tool-phases.js +7 -0
- package/build/tools/code-refactor/codeReuseTool.js +43 -4
- package/build/tools/code-refactor/enhanceAssertionsTool.js +68 -18
- package/build/tools/code-refactor/reuse-outcome.d.ts +109 -0
- package/build/tools/code-refactor/reuse-outcome.js +158 -0
- package/build/tools/code-refactor/reuse-state.d.ts +45 -0
- package/build/tools/code-refactor/reuse-state.js +140 -0
- package/build/tools/enrichTestWithMocksTool.d.ts +28 -0
- package/build/tools/enrichTestWithMocksTool.js +726 -0
- package/build/tools/executeSkyrampTestTool.d.ts +11 -0
- package/build/tools/executeSkyrampTestTool.js +62 -21
- package/build/tools/generate-tests/batchMockGenerationTool.d.ts +106 -0
- package/build/tools/generate-tests/batchMockGenerationTool.js +545 -0
- package/build/tools/generate-tests/generateBatchScenarioRestTool.js +25 -23
- package/build/tools/generate-tests/generateContractRestTool.js +2 -2
- package/build/tools/generate-tests/generateE2ERestTool.d.ts +1 -1
- package/build/tools/generate-tests/generateE2ERestTool.js +1 -1
- package/build/tools/generate-tests/generateLoadRestTool.d.ts +1 -1
- package/build/tools/generate-tests/generateLoadRestTool.js +1 -1
- package/build/tools/generate-tests/generateMockRestTool.d.ts +179 -6
- package/build/tools/generate-tests/generateMockRestTool.js +391 -22
- package/build/tools/generate-tests/loadTestSchema.d.ts +1 -1
- package/build/tools/generate-tests/planGuard.js +2 -22
- package/build/tools/generateEnrichedIntegrationTestTool.d.ts +25 -0
- package/build/tools/generateEnrichedIntegrationTestTool.js +235 -0
- package/build/tools/localDevWorkerComposeTool.d.ts +24 -0
- package/build/tools/localDevWorkerComposeTool.js +264 -0
- package/build/tools/one-click/oneClickTool.d.ts +13 -0
- package/build/tools/one-click/oneClickTool.js +195 -24
- package/build/tools/preflightMockCheckTool.d.ts +2 -0
- package/build/tools/preflightMockCheckTool.js +96 -0
- package/build/tools/queryProxyMocksTool.d.ts +70 -0
- package/build/tools/queryProxyMocksTool.js +521 -0
- package/build/tools/runExistingTestsTool.d.ts +138 -0
- package/build/tools/runExistingTestsTool.js +644 -0
- package/build/tools/submitReportTool.js +40 -2
- package/build/tools/test-management/actionsTool.js +12 -2
- package/build/tools/test-management/analyzeChangesTool.d.ts +2 -1
- package/build/tools/test-management/analyzeChangesTool.js +63 -40
- package/build/tools/test-management/analyzeTestHealthTool.d.ts +11 -0
- package/build/tools/test-management/analyzeTestHealthTool.js +63 -1
- package/build/tools/test-management/registerTestPlanTool.js +55 -7
- package/build/tools/trace/startTraceCollectionTool.js +3 -3
- package/build/types/ExternalTestExecution.d.ts +67 -0
- package/build/types/ExternalTestExecution.js +8 -0
- package/build/types/OneClickCommands.d.ts +1 -1
- package/build/types/Recommendation.d.ts +20 -0
- package/build/types/Recommendation.js +32 -6
- package/build/types/RepositoryAnalysis.d.ts +131 -14
- package/build/types/RepositoryAnalysis.js +16 -2
- package/build/types/ReuseOutcome.d.ts +63 -0
- package/build/types/ReuseOutcome.js +33 -0
- package/build/types/TestAnalysis.d.ts +7 -3
- package/build/types/TestExecution.d.ts +1 -0
- package/build/types/TestTypes.d.ts +25 -7
- package/build/types/TestTypes.js +25 -7
- package/build/types/TestbotPromptOptions.d.ts +35 -0
- package/build/types/TestbotPromptOptions.js +1 -0
- package/build/types/TestbotReport.d.ts +7 -0
- package/build/types/index.d.ts +3 -0
- package/build/types/index.js +1 -0
- package/build/utils/AnalysisStateManager.d.ts +33 -0
- package/build/utils/AnalysisStateManager.js +36 -2
- package/build/utils/analyze-openapi.js +18 -1
- package/build/utils/branchDiff.d.ts +17 -1
- package/build/utils/branchDiff.js +99 -14
- package/build/utils/featureFlags.d.ts +31 -0
- package/build/utils/featureFlags.js +37 -0
- package/build/utils/frontendSelectors.js +0 -1
- package/build/utils/gitStaging.d.ts +5 -0
- package/build/utils/gitStaging.js +1 -1
- package/build/utils/grpcMockValidation.d.ts +1 -0
- package/build/utils/grpcMockValidation.js +49 -0
- package/build/utils/httpMethodValidation.d.ts +4 -0
- package/build/utils/httpMethodValidation.js +15 -0
- package/build/utils/logger.js +1 -1
- package/build/utils/mockCompatibility.d.ts +49 -0
- package/build/utils/mockCompatibility.js +82 -0
- package/build/utils/pom-catalog.d.ts +23 -0
- package/build/utils/pom-catalog.js +30 -0
- package/build/utils/pom-scope/pom-files.d.ts +14 -0
- package/build/utils/pom-scope/pom-files.js +32 -6
- package/build/utils/pom-scope/testIdDiscovery.d.ts +40 -0
- package/build/utils/pom-scope/testIdDiscovery.js +104 -0
- package/build/utils/pom-verify/verify.d.ts +5 -0
- package/build/utils/pom-verify/verify.js +1 -0
- package/build/utils/progress.js +10 -5
- package/build/utils/proxy-terminal.js +3 -3
- package/build/utils/reportVerification.d.ts +7 -2
- package/build/utils/reportVerification.js +9 -3
- package/build/utils/routeParsers.d.ts +3 -9
- package/build/utils/routeParsers.js +79 -4
- package/build/utils/utils.js +2 -2
- package/build/utils/versions.d.ts +4 -3
- package/build/utils/versions.js +3 -1
- package/build/utils/workspaceAuth.d.ts +46 -0
- package/build/utils/workspaceAuth.js +156 -1
- package/build/workspace/frameworks.d.ts +11 -0
- package/build/workspace/frameworks.js +22 -0
- package/build/workspace/testSuites.d.ts +20 -0
- package/build/workspace/testSuites.js +17 -0
- package/build/workspace/workspace.d.ts +206 -24
- package/build/workspace/workspace.js +52 -2
- package/node_modules/playwright/ThirdPartyNotices.txt +319 -266
- package/node_modules/playwright/lib/dom-analyzer/blueprint.js +154 -27
- package/node_modules/playwright/lib/dom-analyzer/crawler.js +2 -2
- package/node_modules/playwright/lib/mcp/browser/tools/pageBlueprint.js +1 -1
- package/node_modules/playwright/lib/mcp/browser/tools/sitemap.js +6 -2
- package/node_modules/playwright/lib/mcp/skyramp/loadTraceTool.js +3 -2
- package/node_modules/playwright/lib/mcp/skyramp/resultCode.js +4 -3
- package/node_modules/playwright/lib/mcp/skyramp/skyRampImport.js +15 -3
- package/node_modules/playwright/lib/mcp/skyramp/specImport.js +781 -0
- package/node_modules/playwright/lib/mcp/skyramp/traceRecordingBackend.js +14 -3
- package/node_modules/playwright/lib/mcp/test/resultCode.test.js +2 -1
- package/node_modules/playwright/lib/mcp/test/skyRampExport.js +1 -1
- package/node_modules/playwright/lib/mcp/test/skyRampExport.test.js +30 -0
- package/node_modules/playwright/lib/transform/babelBundleImpl.js +200 -199
- package/node_modules/playwright/node_modules/playwright-core/ThirdPartyNotices.txt +3 -3
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/.package-lock.json +3 -3
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/adapter/aws-lambda/handler.js +16 -25
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/adapter/bun/websocket.js +3 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/adapter/lambda-edge/handler.js +20 -4
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/adapter/aws-lambda/handler.js +16 -25
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/adapter/bun/websocket.js +3 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/adapter/lambda-edge/handler.js +20 -4
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/client/client.js +10 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/client/utils.js +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/helper/css/common.js +3 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/helper/css/index.js +9 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/jsx/base.js +8 -14
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/jsx/components.js +41 -21
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/jsx/context.js +131 -5
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/jsx/streaming.js +9 -7
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/middleware/bearer-auth/index.js +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/middleware/cache/index.js +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/middleware/compress/index.js +2 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/middleware/cors/index.js +2 -5
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/middleware/etag/index.js +2 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/middleware/language/language.js +10 -32
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/middleware/method-override/index.js +5 -3
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/middleware/serve-static/index.js +2 -2
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/middleware/timing/timing.js +3 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/router/trie-router/node.js +9 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/utils/body.js +12 -4
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/utils/buffer.js +2 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/utils/ipaddr.js +6 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/cjs/validator/validator.js +3 -3
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/client/client.js +10 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/client/utils.js +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/helper/css/common.js +3 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/helper/css/index.js +9 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/jsx/base.js +15 -15
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/jsx/components.js +42 -22
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/jsx/context.js +129 -5
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/jsx/streaming.js +10 -8
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/middleware/bearer-auth/index.js +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/middleware/cache/index.js +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/middleware/compress/index.js +2 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/middleware/cors/index.js +2 -5
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/middleware/etag/index.js +2 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/middleware/language/language.js +10 -32
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/middleware/method-override/index.js +5 -3
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/middleware/serve-static/index.js +2 -2
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/middleware/timing/timing.js +3 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/router/trie-router/node.js +9 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/adapter/aws-lambda/handler.d.ts +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/adapter/lambda-edge/handler.d.ts +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/helper/websocket/index.d.ts +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/jsx/base.d.ts +1 -3
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/jsx/context.d.ts +39 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/middleware/context-storage/index.d.ts +2 -2
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/middleware/language/language.d.ts +18 -0
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/utils/body.d.ts +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/types/utils/types.d.ts +1 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/utils/body.js +12 -4
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/utils/buffer.js +2 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/utils/ipaddr.js +6 -1
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/validator/validator.js +3 -3
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/package.json +29 -22
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/package-lock.json +3 -3
- package/node_modules/playwright/node_modules/playwright-core/lib/generated/pollingRecorderSource.js +1 -1
- package/node_modules/playwright/node_modules/playwright-core/lib/server/codegen/skyramp/jsonlReader.js +5 -1
- package/node_modules/playwright/node_modules/playwright-core/lib/server/codegen/skyramp/specReader.js +781 -0
- package/node_modules/playwright/node_modules/playwright-core/lib/server/recorder/recorderApp.js +25 -6
- package/node_modules/playwright/node_modules/playwright-core/lib/server/recorder/skyramp/replayEngine.js +3 -1
- package/node_modules/playwright/node_modules/playwright-core/lib/utils.js +2 -0
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/htmlReport/index.html +253 -27
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/recorder/assets/{codeMirrorModule-D0BjbCb7.js → codeMirrorModule-DtudTj_v.js} +1 -1
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/recorder/assets/index-BpDwp16L.js +422 -0
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/recorder/index.html +1 -1
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/assets/{codeMirrorModule-Bzd72-bG.js → codeMirrorModule-FNMuBzX1.js} +1 -1
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/assets/defaultSettingsView-Co9upU5h.js +1035 -0
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/index.DXNIQ_dx.js +2 -0
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/index.html +2 -2
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/uiMode.CIKB3XSv.js +5 -0
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/uiMode.html +2 -2
- package/node_modules/playwright/node_modules/playwright-core/package.json +1 -1
- package/node_modules/playwright/node_modules/playwright-core/src/generated/pollingRecorderSource.ts +1 -1
- package/node_modules/playwright/node_modules/playwright-core/src/server/codegen/skyramp/jsonlReader.ts +4 -0
- package/node_modules/playwright/node_modules/playwright-core/src/server/codegen/skyramp/specReader.ts +1028 -0
- package/node_modules/playwright/node_modules/playwright-core/src/server/recorder/recorderApp.ts +31 -8
- package/node_modules/playwright/node_modules/playwright-core/src/server/recorder/skyramp/replayEngine.ts +1 -0
- package/node_modules/playwright/node_modules/playwright-core/src/utils.ts +1 -0
- package/node_modules/playwright/package.json +1 -1
- package/package.json +12 -6
- package/node_modules/playwright/node_modules/playwright-core/bundles/mcp/node_modules/hono/dist/tsconfig.build.tsbuildinfo +0 -1
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/recorder/assets/index-lvTRGFx-.js +0 -193
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/assets/defaultSettingsView-DzxTioTK.js +0 -809
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/index.BGc30U3S.js +0 -2
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/uiMode.IaDrb29A.js +0 -5
|
@@ -9,11 +9,11 @@ import { logger } from "../utils/logger.js";
|
|
|
9
9
|
import { TestExecutionStatus, } from "../types/TestExecution.js";
|
|
10
10
|
import { TestType } from "../types/TestTypes.js";
|
|
11
11
|
import { buildContainerEnv } from "./containerEnv.js";
|
|
12
|
-
import {
|
|
12
|
+
import { EXECUTOR_DOCKER_IMAGE } from "../utils/versions.js";
|
|
13
13
|
import { walkDir } from "../utils/fileWalk.js";
|
|
14
|
+
export { EXECUTOR_DOCKER_IMAGE };
|
|
14
15
|
const DEFAULT_TIMEOUT = 300000; // 5 minutes
|
|
15
16
|
const MAX_CONCURRENT_EXECUTIONS = 5;
|
|
16
|
-
export const EXECUTOR_DOCKER_IMAGE = `skyramp/executor:${SKYRAMP_IMAGE_VERSION}`;
|
|
17
17
|
const DOCKER_PLATFORM = "linux/amd64";
|
|
18
18
|
const EXECUTION_PROGRESS_INTERVAL = 10000; // 10 seconds between progress updates during execution
|
|
19
19
|
// Temp file with valid empty JSON — used instead of /dev/null for .json config files
|
|
@@ -54,8 +54,11 @@ export const PLAYWRIGHT_CONFIG_FILES = [
|
|
|
54
54
|
"playwright.config.js",
|
|
55
55
|
"playwright.config.mjs",
|
|
56
56
|
];
|
|
57
|
-
// Directories
|
|
58
|
-
|
|
57
|
+
// Directories the recursive shadow scans must never descend into. node_modules
|
|
58
|
+
// IS mounted (see mountRepoTree) — but walking it would shadow every package's
|
|
59
|
+
// own package.json with empty JSON via MOUNT_NULL_ITEMS, breaking resolution
|
|
60
|
+
// for the whole tree.
|
|
61
|
+
export const MOUNT_SCAN_SKIP_DIRS = [
|
|
59
62
|
"node_modules",
|
|
60
63
|
];
|
|
61
64
|
// Reserved container subdir under /home/user where a cross-repo test repository
|
|
@@ -354,7 +357,7 @@ export function detectSessionFiles(testFilePath) {
|
|
|
354
357
|
*/
|
|
355
358
|
export function findExcludedPaths(dir, excludedItems) {
|
|
356
359
|
const results = [];
|
|
357
|
-
const shouldSkipDir = (entry) => excludedItems.includes(entry.name) ||
|
|
360
|
+
const shouldSkipDir = (entry) => excludedItems.includes(entry.name) || MOUNT_SCAN_SKIP_DIRS.includes(entry.name);
|
|
358
361
|
for (const [entry, fullPath] of walkDir(dir, { shouldSkipDir })) {
|
|
359
362
|
// Only shadow files — mounting /dev/null to a directory target causes Docker errors
|
|
360
363
|
if (excludedItems.includes(entry.name)) {
|
|
@@ -364,18 +367,23 @@ export function findExcludedPaths(dir, excludedItems) {
|
|
|
364
367
|
return results;
|
|
365
368
|
}
|
|
366
369
|
/**
|
|
367
|
-
* Find every
|
|
368
|
-
*
|
|
369
|
-
*
|
|
370
|
-
*
|
|
371
|
-
*
|
|
372
|
-
*
|
|
370
|
+
* Find every `node_modules` directory under `dir`, including the top-level
|
|
371
|
+
* `<dir>/node_modules`. Never descends into a `node_modules`. Used to shadow
|
|
372
|
+
* SHADOWED_NESTED_PACKAGES inside each one: a repo-local `@playwright/test`
|
|
373
|
+
* becomes a second physical copy and trips Playwright's "Requiring
|
|
374
|
+
* @playwright/test second time" guard.
|
|
375
|
+
*
|
|
376
|
+
* The top-level one is deliberately NOT special-cased (SKYR-4140). When
|
|
377
|
+
* `workspacePath` is itself an npm package root — the standard `tests/<suite>/`
|
|
378
|
+
* layout — its node_modules IS the only one, so skipping it left the shadow
|
|
379
|
+
* machinery with nothing to act on and no customer dependency resolvable.
|
|
380
|
+
*
|
|
373
381
|
* Skips `.git` (nothing importable lives there) and does not follow symlinks —
|
|
374
382
|
* by design (a symlinked nested node_modules either dangles in-container,
|
|
375
383
|
* falling through to NODE_PATH's global copy, or its real-path target is
|
|
376
384
|
* walked directly).
|
|
377
385
|
*/
|
|
378
|
-
export function
|
|
386
|
+
export function findNodeModulesDirs(dir) {
|
|
379
387
|
const results = [];
|
|
380
388
|
const walk = (current) => {
|
|
381
389
|
let entries;
|
|
@@ -392,8 +400,7 @@ export function findNestedNodeModules(dir) {
|
|
|
392
400
|
continue;
|
|
393
401
|
const full = path.join(current, entry.name);
|
|
394
402
|
if (entry.name === "node_modules") {
|
|
395
|
-
|
|
396
|
-
results.push(full); // skip the top-level node_modules
|
|
403
|
+
results.push(full);
|
|
397
404
|
continue; // never descend into a node_modules
|
|
398
405
|
}
|
|
399
406
|
walk(full);
|
|
@@ -565,10 +572,15 @@ export class TestExecutionService {
|
|
|
565
572
|
testFilePath,
|
|
566
573
|
options.testType,
|
|
567
574
|
];
|
|
575
|
+
const networkMode = options.dockerNetwork?.trim()
|
|
576
|
+
? options.dockerNetwork.trim()
|
|
577
|
+
: options.useHostNetwork && process.platform === "linux"
|
|
578
|
+
? "host"
|
|
579
|
+
: undefined;
|
|
568
580
|
// Prepare host config with mounts
|
|
569
581
|
const hostConfig = {
|
|
570
582
|
ExtraHosts: ["host.docker.internal:host-gateway"],
|
|
571
|
-
...(
|
|
583
|
+
...(networkMode ? { NetworkMode: networkMode } : {}),
|
|
572
584
|
Mounts: [
|
|
573
585
|
{
|
|
574
586
|
Type: "bind",
|
|
@@ -588,17 +600,16 @@ export class TestExecutionService {
|
|
|
588
600
|
hostConfig.Mounts.push(mount);
|
|
589
601
|
};
|
|
590
602
|
// Mount one repo tree (the workspace, or a cross-repo test repository) into
|
|
591
|
-
// the container
|
|
603
|
+
// the container.
|
|
592
604
|
//
|
|
593
605
|
// Each top-level entry is bind-mounted at the canonical container path and —
|
|
594
606
|
// when mirrorToHost is set — at its host-absolute path too. The dual mount
|
|
595
607
|
// lets the test resolve any absolute reference the codegen happens to embed
|
|
596
608
|
// (storageState, fixture paths, snapshots) — including the host workspace
|
|
597
609
|
// path that Playwright's TypeScript loader sometimes produces from
|
|
598
|
-
// `__dirname` — without needing source-code detection.
|
|
599
|
-
// (
|
|
600
|
-
//
|
|
601
|
-
// PLAYWRIGHT_CONFIG_FILES shadows (minimal config) are applied at both
|
|
610
|
+
// `__dirname` — without needing source-code detection. MOUNT_NULL_ITEMS
|
|
611
|
+
// shadows (package.json → empty JSON, etc.), node_modules package shadows,
|
|
612
|
+
// and PLAYWRIGHT_CONFIG_FILES shadows (minimal config) are applied at both
|
|
602
613
|
// targets too so the protections survive regardless of which path the test
|
|
603
614
|
// resolves to.
|
|
604
615
|
//
|
|
@@ -606,7 +617,7 @@ export class TestExecutionService {
|
|
|
606
617
|
// later mounts over earlier ones, so the top-level entry mounts must be
|
|
607
618
|
// pushed BEFORE the shadow mounts that override paths inside them.
|
|
608
619
|
//
|
|
609
|
-
// The three recursive scans (findExcludedPaths × 2 +
|
|
620
|
+
// The three recursive scans (findExcludedPaths × 2 + findNodeModulesDirs)
|
|
610
621
|
// are deliberately kept as separate walks rather than fused into one pass:
|
|
611
622
|
// each skips node_modules/.git so the cost is small, and separate walks keep
|
|
612
623
|
// each shadow category's semantics independently testable.
|
|
@@ -618,11 +629,13 @@ export class TestExecutionService {
|
|
|
618
629
|
// otherwise the entry mount would win the dedup race and the repo's own
|
|
619
630
|
// config (which may import dotenv, or simply isn't the minimal/generated
|
|
620
631
|
// one) would leak into the container.
|
|
632
|
+
//
|
|
633
|
+
// node_modules is NOT filtered out (SKYR-4140): it carries the customer's
|
|
634
|
+
// test-support deps, and the per-package shadows below neutralise the only
|
|
635
|
+
// copies that must not load from the repo.
|
|
621
636
|
const entriesToMount = fs
|
|
622
637
|
.readdirSync(hostRoot)
|
|
623
|
-
.filter((file) => !
|
|
624
|
-
!MOUNT_NULL_ITEMS.includes(file) &&
|
|
625
|
-
!PLAYWRIGHT_CONFIG_FILES.includes(file));
|
|
638
|
+
.filter((file) => !MOUNT_NULL_ITEMS.includes(file) && !PLAYWRIGHT_CONFIG_FILES.includes(file));
|
|
626
639
|
for (const file of entriesToMount) {
|
|
627
640
|
const source = path.join(hostRoot, file);
|
|
628
641
|
pushMount({ Type: "bind", Target: path.join(containerRoot, file), Source: source });
|
|
@@ -639,10 +652,9 @@ export class TestExecutionService {
|
|
|
639
652
|
pushMount({ Type: "bind", Source: source, Target: absolutePath });
|
|
640
653
|
}
|
|
641
654
|
}
|
|
642
|
-
// Shadow SHADOWED_NESTED_PACKAGES inside every
|
|
643
|
-
//
|
|
644
|
-
|
|
645
|
-
for (const nested of findNestedNodeModules(hostRoot)) {
|
|
655
|
+
// Shadow SHADOWED_NESTED_PACKAGES inside every mounted node_modules — the
|
|
656
|
+
// repo's own top-level one included (see findNodeModulesDirs).
|
|
657
|
+
for (const nested of findNodeModulesDirs(hostRoot)) {
|
|
646
658
|
for (const pkg of SHADOWED_NESTED_PACKAGES) {
|
|
647
659
|
const pkgPath = path.join(nested, pkg);
|
|
648
660
|
if (!fs.existsSync(pkgPath))
|
|
@@ -706,6 +718,22 @@ export class TestExecutionService {
|
|
|
706
718
|
if (crossRepoTestRoot) {
|
|
707
719
|
mountRepoTree(crossRepoTestRoot, path.join(containerMountPath, TEST_REPO_CONTAINER_SUBDIR), true);
|
|
708
720
|
}
|
|
721
|
+
// runner.sh invokes `npx playwright test`, and npx resolves binaries from
|
|
722
|
+
// <cwd>/node_modules/.bin before PATH — cwd is always containerMountPath. Now
|
|
723
|
+
// that node_modules is mounted (SKYR-4140), a repo-local .bin/playwright would
|
|
724
|
+
// run instead of the image's global CLI. The per-package shadows above do not
|
|
725
|
+
// cover it under a pnpm layout, where .bin/playwright symlinks into .pnpm/
|
|
726
|
+
// rather than into node_modules/playwright. Shadow this one .bin — the only
|
|
727
|
+
// one npx can reach — so binary resolution falls through to PATH as before.
|
|
728
|
+
// Pushed after mountRepoTree so it layers over the node_modules entry mount.
|
|
729
|
+
if (fs.existsSync(path.join(workspacePath, "node_modules", ".bin"))) {
|
|
730
|
+
pushMount({
|
|
731
|
+
Type: "bind",
|
|
732
|
+
Source: EMPTY_DIR_PATH,
|
|
733
|
+
Target: path.join(containerMountPath, "node_modules", ".bin"),
|
|
734
|
+
ReadOnly: true,
|
|
735
|
+
});
|
|
736
|
+
}
|
|
709
737
|
// Mount video output directory for browser tests (writable)
|
|
710
738
|
if (browserTest && videoHostDir) {
|
|
711
739
|
pushMount({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { SkyrampClient } from "@skyramp/skyramp";
|
|
2
2
|
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
3
|
-
import { TestType } from "../types/TestTypes.js";
|
|
3
|
+
import { TestType, MOCK_TYPE } from "../types/TestTypes.js";
|
|
4
4
|
export interface BaseTestParams {
|
|
5
5
|
endpointURL?: string;
|
|
6
6
|
method?: string;
|
|
@@ -50,7 +50,7 @@ export declare abstract class TestGenerationService {
|
|
|
50
50
|
generateTest(params: BaseTestParams & Record<string, any>): Promise<CallToolResult>;
|
|
51
51
|
protected validateInputs(params: BaseTestParams): CallToolResult;
|
|
52
52
|
protected abstract buildGenerationOptions(params: BaseTestParams & Record<string, any>): any;
|
|
53
|
-
protected abstract getTestType(): TestType;
|
|
53
|
+
protected abstract getTestType(): TestType | typeof MOCK_TYPE;
|
|
54
54
|
protected handleApiAnalysis(params: BaseTestParams): Promise<CallToolResult | null>;
|
|
55
55
|
private static readonly STANDARD_HEADERS;
|
|
56
56
|
private static simpleWildcardMatch;
|
|
@@ -2,10 +2,11 @@ import path from "path";
|
|
|
2
2
|
import fs from "fs";
|
|
3
3
|
import { SkyrampClient } from "@skyramp/skyramp";
|
|
4
4
|
import { analyzeOpenAPIWithGivenEndpoint } from "../utils/analyze-openapi.js";
|
|
5
|
-
import { isAuthorizationHeaderName, KNOWN_AUTH_HEADERS,
|
|
5
|
+
import { isAuthorizationHeaderName, KNOWN_AUTH_HEADERS, resolveAuthFromWorkspace, getWorkspaceSkipTLSVerify, getWorkspaceDefaultQueryParams, mergeQueryParamsString, } from "../utils/workspaceAuth.js";
|
|
6
6
|
import { getPathParameterValidationError, OUTPUT_DIR_FIELD_NAME, PATH_PARAMS_FIELD_NAME, QUERY_PARAMS_FIELD_NAME, FORM_PARAMS_FIELD_NAME, validateParams, validatePath, validateRequestData, } from "../utils/utils.js";
|
|
7
7
|
import { getEntryPoint } from "../utils/telemetry.js";
|
|
8
8
|
import { getLanguageSteps } from "../utils/language-helper.js";
|
|
9
|
+
import { TestType } from "../types/TestTypes.js";
|
|
9
10
|
import { logger } from "../utils/logger.js";
|
|
10
11
|
import { normalizeLanguageParams } from "../utils/normalizeParams.js";
|
|
11
12
|
import { stageGeneratedPaths, resolveOutputDir } from "../utils/gitStaging.js";
|
|
@@ -24,6 +25,19 @@ export function deriveEffectiveFramework(language, framework) {
|
|
|
24
25
|
const lang = (language ?? "").trim().toLowerCase();
|
|
25
26
|
return lang === "typescript" || lang === "javascript" ? "playwright" : "";
|
|
26
27
|
}
|
|
28
|
+
/**
|
|
29
|
+
* Test types whose generation is driven by a recorded Playwright trace, not a
|
|
30
|
+
* live query-string request the same way contract/fuzz/smoke/load/integration
|
|
31
|
+
* are. Their schemas (uiTestSchema, e2eTestSchema) don't expose a queryParams
|
|
32
|
+
* field at all, so there's no way for a caller to override or even know this
|
|
33
|
+
* field exists — injecting an unrequested, uneditable workspace
|
|
34
|
+
* defaultQueryParams value into that path is not what the design intends
|
|
35
|
+
* (SKYR-4050).
|
|
36
|
+
*/
|
|
37
|
+
const SKIP_DEFAULT_QUERY_PARAMS_TEST_TYPES = new Set([
|
|
38
|
+
TestType.UI,
|
|
39
|
+
TestType.E2E,
|
|
40
|
+
]);
|
|
27
41
|
export class TestGenerationService {
|
|
28
42
|
client;
|
|
29
43
|
constructor() {
|
|
@@ -316,29 +330,15 @@ The generated test file remains unchanged and ready to use as-is.
|
|
|
316
330
|
async executeGeneration(generateOptions) {
|
|
317
331
|
try {
|
|
318
332
|
// Auto-resolve auth from workspace config when authHeader was not explicitly provided.
|
|
319
|
-
// undefined =
|
|
333
|
+
// undefined = auto-resolve; "" = caller explicitly said skip-auth.
|
|
320
334
|
if (generateOptions.authHeader === undefined) {
|
|
321
335
|
try {
|
|
322
336
|
const repoPath = generateOptions.outputDir || process.cwd();
|
|
323
|
-
const
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
if (wsAuth.authType === WorkspaceAuthType.ApiKey && !resolvedHeader) {
|
|
329
|
-
logger.warning("workspace.yml has authType: apiKey but no authHeader is set — " +
|
|
330
|
-
"requests will be sent without an auth header and will likely receive 401/403. " +
|
|
331
|
-
"Add authHeader: <X-Your-Key-Header> to .skyramp/workspace.yml.");
|
|
332
|
-
}
|
|
333
|
-
if (resolvedHeader && wsAuth.authType !== WorkspaceAuthType.None) {
|
|
334
|
-
logger.info("authHeader not provided — resolved from workspace config", {
|
|
335
|
-
authHeader: resolvedHeader,
|
|
336
|
-
authType: wsAuth.authType,
|
|
337
|
-
});
|
|
338
|
-
generateOptions.authHeader = resolvedHeader;
|
|
339
|
-
if (isAuthorizationHeaderName(resolvedHeader)) {
|
|
340
|
-
generateOptions.authScheme =
|
|
341
|
-
generateOptions.authScheme ?? wsAuth.authScheme ?? getAuthScheme(wsAuth.authType);
|
|
337
|
+
const resolved = await resolveAuthFromWorkspace(repoPath, generateOptions.authHeader, generateOptions.authScheme);
|
|
338
|
+
if (resolved) {
|
|
339
|
+
generateOptions.authHeader = resolved.authHeader;
|
|
340
|
+
if (resolved.authScheme !== undefined) {
|
|
341
|
+
generateOptions.authScheme = resolved.authScheme;
|
|
342
342
|
}
|
|
343
343
|
}
|
|
344
344
|
}
|
|
@@ -364,6 +364,24 @@ The generated test file remains unchanged and ready to use as-is.
|
|
|
364
364
|
logger.warning("Could not resolve skipTLSVerify from workspace config");
|
|
365
365
|
}
|
|
366
366
|
}
|
|
367
|
+
// Workspace-declared default query params (SKYR-4050): api.defaultQueryParams
|
|
368
|
+
// are attached to every generated request for the service. Existing
|
|
369
|
+
// queryParams entries (explicit caller values) always win on a key collision.
|
|
370
|
+
if (!SKIP_DEFAULT_QUERY_PARAMS_TEST_TYPES.has(this.getTestType())) {
|
|
371
|
+
try {
|
|
372
|
+
const repoPath = generateOptions.outputDir || process.cwd();
|
|
373
|
+
const defaults = await getWorkspaceDefaultQueryParams(repoPath);
|
|
374
|
+
if (defaults) {
|
|
375
|
+
generateOptions.queryParams = mergeQueryParamsString(generateOptions.queryParams, defaults);
|
|
376
|
+
logger.info("Merged workspace defaultQueryParams into queryParams", {
|
|
377
|
+
keys: Object.keys(defaults),
|
|
378
|
+
});
|
|
379
|
+
}
|
|
380
|
+
}
|
|
381
|
+
catch {
|
|
382
|
+
logger.warning("Could not resolve default query params from workspace config");
|
|
383
|
+
}
|
|
384
|
+
}
|
|
367
385
|
if (generateOptions.traceFilePath) {
|
|
368
386
|
const traceAuth = this.extractAuthFromTrace(generateOptions.traceFilePath, generateOptions.generateInclude, generateOptions.generateExclude);
|
|
369
387
|
if (traceAuth) {
|
|
@@ -14,7 +14,9 @@ export function rewriteLocalhostForDocker(url) {
|
|
|
14
14
|
*/
|
|
15
15
|
export function buildContainerEnv(options, saveStoragePath, hostEnv = process.env) {
|
|
16
16
|
const env = [
|
|
17
|
-
|
|
17
|
+
// Omit entirely when empty so os.getenv() returns None in the test —
|
|
18
|
+
// unauthenticated endpoints won't send an empty auth header (E7).
|
|
19
|
+
...(options.token ? [`SKYRAMP_TEST_TOKEN=${options.token}`] : []),
|
|
18
20
|
"SKYRAMP_IN_DOCKER=true",
|
|
19
21
|
];
|
|
20
22
|
// Skyramp-generated tests are standalone HTTP tests that never need host repo
|
|
@@ -42,6 +44,30 @@ export function buildContainerEnv(options, saveStoragePath, hostEnv = process.en
|
|
|
42
44
|
env.push(`${key}=${shouldRewrite ? rewriteLocalhostForDocker(val) : val}`);
|
|
43
45
|
}
|
|
44
46
|
}
|
|
47
|
+
// Credentials that generated UI tests read from the environment instead of
|
|
48
|
+
// carrying as literals (SKYR-3862). Without this the container never sees
|
|
49
|
+
// them and every generated login fails its guard.
|
|
50
|
+
//
|
|
51
|
+
// Forwarded on presence, not truthiness: the generated guard deliberately
|
|
52
|
+
// distinguishes an unset variable (a misconfiguration, fails fast) from one
|
|
53
|
+
// set to "" (valid on forms that accept a blank password). A truthy check —
|
|
54
|
+
// as used for the URL vars above — would drop the empty case and collapse it
|
|
55
|
+
// into the failure case.
|
|
56
|
+
//
|
|
57
|
+
// TODO(SKYR-4110): only ONE credential pair is forwarded, because testbot
|
|
58
|
+
// exports only the first credential from its `uiCredentials` input. That input
|
|
59
|
+
// was designed to carry several, so the agent can pick per test case by
|
|
60
|
+
// authorization role — so a multi-role suite can get a credential its test did
|
|
61
|
+
// not expect, surfacing as a false 403. The fix is a keyed form
|
|
62
|
+
// (SKYRAMP_UI_PASSWORD_<KEY>), which needs no new forwarding logic here: the
|
|
63
|
+
// loop above already forwards SKYRAMP_TEST_SERVICE_URL_* by prefix, so the
|
|
64
|
+
// same approach applies. Keep the presence-not-truthiness rule when it lands.
|
|
65
|
+
for (const key of ["SKYRAMP_UI_USERNAME", "SKYRAMP_UI_PASSWORD"]) {
|
|
66
|
+
const val = hostEnv[key];
|
|
67
|
+
if (val !== undefined) {
|
|
68
|
+
env.push(`${key}=${val}`);
|
|
69
|
+
}
|
|
70
|
+
}
|
|
45
71
|
if (hostEnv.SKYRAMP_DEBUG) {
|
|
46
72
|
env.push(`SKYRAMP_DEBUG=${hostEnv.SKYRAMP_DEBUG}`);
|
|
47
73
|
}
|
package/build/tool-phases.js
CHANGED
|
@@ -11,7 +11,11 @@ export const TOOL_PHASE_MAP = {
|
|
|
11
11
|
skyramp_ui_test_generation: "generating",
|
|
12
12
|
skyramp_batch_scenario_test_generation: "generating",
|
|
13
13
|
skyramp_mock_generation: "generating",
|
|
14
|
+
skyramp_batch_mock_generation: "generating",
|
|
15
|
+
skyramp_generate_enriched_integration_test: "generating",
|
|
16
|
+
skyramp_enrich_test_with_mocks: "generating",
|
|
14
17
|
skyramp_execute_test: { before: "maintaining", after: "executing" },
|
|
18
|
+
skyramp_run_existing_tests: { before: "maintaining", after: "executing" },
|
|
15
19
|
skyramp_analyze_test_health: "maintaining",
|
|
16
20
|
skyramp_submit_report: "reporting",
|
|
17
21
|
};
|
|
@@ -30,6 +34,7 @@ export const TOOLS_WITHOUT_PHASE = new Set([
|
|
|
30
34
|
"skyramp_init_scan",
|
|
31
35
|
"skyramp_init_workspace",
|
|
32
36
|
"skyramp_one_click_tool",
|
|
37
|
+
"skyramp_setup_local_dev_worker",
|
|
33
38
|
"skyramp_actions",
|
|
34
39
|
"skyramp_start_trace_collection",
|
|
35
40
|
"skyramp_stop_trace_collection",
|
|
@@ -37,4 +42,6 @@ export const TOOLS_WITHOUT_PHASE = new Set([
|
|
|
37
42
|
"skyramp_modularization",
|
|
38
43
|
"skyramp_reuse_code",
|
|
39
44
|
"skyramp_enhance_assertions",
|
|
45
|
+
"skyramp_preflight_mock_check",
|
|
46
|
+
"skyramp_query_proxy_mocks",
|
|
40
47
|
]);
|
|
@@ -4,9 +4,11 @@ import { getCodeReusePrompt, isPomAwareTarget } from "../../prompts/code-reuse.j
|
|
|
4
4
|
import { selectScopedPoms } from "../../utils/pom-scope/index.js";
|
|
5
5
|
import { verifyReuse } from "../../utils/pom-verify/index.js";
|
|
6
6
|
import { infraGateFailure, zeroReuseGateFailure, composeVerifyText } from "./verify-gates.js";
|
|
7
|
+
import { recordCandidates, recordNoPomLayer, recordVerifyOutcome } from "./reuse-state.js";
|
|
7
8
|
import { codeRefactoringSchema, languageSchema, } from "../../types/TestTypes.js";
|
|
8
9
|
import { SKYRAMP_UTILS_HEADER } from "../../utils/utils.js";
|
|
9
10
|
import { AnalyticsService } from "../../services/AnalyticsService.js";
|
|
11
|
+
import { isPomReuseEnabled } from "../../utils/featureFlags.js";
|
|
10
12
|
import { stageGeneratedPaths } from "../../utils/gitStaging.js";
|
|
11
13
|
const codeReuseSchema = z.object({
|
|
12
14
|
testFile: z
|
|
@@ -25,6 +27,12 @@ const codeReuseSchema = z.object({
|
|
|
25
27
|
.describe("Verify a previously written refactored test's POM calls against source instead of returning the reuse prompt"),
|
|
26
28
|
});
|
|
27
29
|
const TOOL_NAME = "skyramp_reuse_code";
|
|
30
|
+
// Only advertised when SKYRAMP_FEATURE_POM_REUSE=1 — with the flag off this tool
|
|
31
|
+
// never takes the POM path, so describing it would promise behavior it won't do.
|
|
32
|
+
const POM_AWARE_MODE_DESCRIPTION = `
|
|
33
|
+
|
|
34
|
+
**POM-AWARE MODE (TypeScript/JavaScript + Playwright):**
|
|
35
|
+
For projects with \`language: "typescript" or "javascript"\` and \`framework: "playwright"\`, this tool first checks whether the project has an existing Page Object Model (POM) library (\`pageobjects/\` directories or \`*.page.ts\` / \`*.page.js\` files). If POMs are found, the test is refactored to use those POM classes and methods — replacing raw inline locators with the existing abstractions. SkyrampUtils consolidation is skipped on this path. If no POMs are found, the tool falls back to the standard SkyrampUtils path. New POM creation is out of scope — existing POMs are reused only. After POM-aware code reuse, do NOT call skyramp_modularization — on this path that supersedes WORKFLOW SUMMARY step 6.`;
|
|
28
36
|
export function registerCodeReuseTool(server) {
|
|
29
37
|
server.registerTool(TOOL_NAME, {
|
|
30
38
|
description: `Analyzes code for reuse opportunities and enforces code reuse principles.
|
|
@@ -57,10 +65,7 @@ export function registerCodeReuseTool(server) {
|
|
|
57
65
|
|
|
58
66
|
**MANDATORY**: ONLY ALLOW CODE REUSE IF THE IS TRACE BASED FLAG IS SET TO TRUE ELSE DO NOT ALLOW CODE REUSE AND LEAVE THE TEST FILE AS IS.
|
|
59
67
|
**CRITICAL**: NON TRACE BASED TESTS ARE ALREADY MODULARIZED AND DO NOT NEED CODE REUSE.
|
|
60
|
-
The tool will provide step-by-step instructions that MUST be followed exactly
|
|
61
|
-
|
|
62
|
-
**POM-AWARE MODE (TypeScript/JavaScript + Playwright):**
|
|
63
|
-
For projects with \`language: "typescript" or "javascript"\` and \`framework: "playwright"\`, this tool first checks whether the project has an existing Page Object Model (POM) library (\`pageobjects/\` directories or \`*.page.ts\` / \`*.page.js\` files). If POMs are found, the test is refactored to use those POM classes and methods — replacing raw inline locators with the existing abstractions. SkyrampUtils consolidation is skipped on this path. If no POMs are found, the tool falls back to the standard SkyrampUtils path. New POM creation is out of scope — existing POMs are reused only. After POM-aware code reuse, do NOT call skyramp_modularization.`,
|
|
68
|
+
The tool will provide step-by-step instructions that MUST be followed exactly.${isPomReuseEnabled() ? POM_AWARE_MODE_DESCRIPTION : ""}`,
|
|
64
69
|
inputSchema: codeReuseSchema.shape,
|
|
65
70
|
_meta: {
|
|
66
71
|
keywords: [
|
|
@@ -75,9 +80,26 @@ export function registerCodeReuseTool(server) {
|
|
|
75
80
|
let errorResult;
|
|
76
81
|
try {
|
|
77
82
|
if (params.verify) {
|
|
83
|
+
// The verify pass is POM-only, and it is the sole writer of the report's
|
|
84
|
+
// reuse summary — so with the flag off a stale instruction to verify must
|
|
85
|
+
// not run it, or a POM-less run would still emit POM reuse numbers.
|
|
86
|
+
if (!isPomReuseEnabled()) {
|
|
87
|
+
return {
|
|
88
|
+
content: [
|
|
89
|
+
{
|
|
90
|
+
type: "text",
|
|
91
|
+
text: "VERIFICATION SKIPPED — POM-aware code reuse is disabled. Nothing to verify; continue.",
|
|
92
|
+
},
|
|
93
|
+
],
|
|
94
|
+
};
|
|
95
|
+
}
|
|
78
96
|
try {
|
|
79
97
|
const r = await verifyReuse(params.testFile, params.language);
|
|
80
98
|
const gate = (await infraGateFailure(params, r)) ?? (await zeroReuseGateFailure(params, r));
|
|
99
|
+
// Record what this pass established before returning the text report:
|
|
100
|
+
// every number in it is already in hand here, so the agent is never
|
|
101
|
+
// asked to read one back out and retype it later.
|
|
102
|
+
await recordVerifyOutcome(params.testFile, r, gate !== undefined, params.language);
|
|
81
103
|
return { content: [{ type: "text", text: composeVerifyText(gate, r) }] };
|
|
82
104
|
}
|
|
83
105
|
catch (err) {
|
|
@@ -110,11 +132,28 @@ export function registerCodeReuseTool(server) {
|
|
|
110
132
|
});
|
|
111
133
|
if (tier1.length + tier2.length > 0) {
|
|
112
134
|
scopedPoms = { tier1, tier2 };
|
|
135
|
+
// Only report candidates found through the conventional POM globs.
|
|
136
|
+
//
|
|
137
|
+
// The selector-grep fallback also matches ordinary in-repo frontend
|
|
138
|
+
// source — app components legitimately contain the spec's test-ids by
|
|
139
|
+
// construction — so in a repo with no page-object layer at all it still
|
|
140
|
+
// yields "candidates". Reporting those would render, on a POM-less repo,
|
|
141
|
+
// "4 candidate POM files detected" next to zero reuse: each number true
|
|
142
|
+
// in isolation, but together they assert reusable page objects existed
|
|
143
|
+
// and were ignored. `zeroReuseGateFailure` already draws this exact line
|
|
144
|
+
// for the same reason; the report has to draw it too.
|
|
145
|
+
//
|
|
146
|
+
// The agent is still handed the grep-discovered files to consider —
|
|
147
|
+
// only the customer-facing count is withheld.
|
|
148
|
+
if (diagnostics.discovery === "globs") {
|
|
149
|
+
await recordCandidates(params.testFile, tier1.length);
|
|
150
|
+
}
|
|
113
151
|
}
|
|
114
152
|
else if (diagnostics.selectors > 0 && diagnostics.discovery !== "skipped-too-large") {
|
|
115
153
|
// A clean scan ran (glob or selector-grep) and found zero overlap — distinct from
|
|
116
154
|
// "scoping wasn't attempted" (no selectors) or "scan was skipped" (repo too large).
|
|
117
155
|
scopedPoms = { tier1: [], tier2: [], scannedNoOverlap: true };
|
|
156
|
+
await recordNoPomLayer(params.testFile);
|
|
118
157
|
}
|
|
119
158
|
logger.info("POM pre-scoping", {
|
|
120
159
|
...diagnostics,
|
|
@@ -5,6 +5,7 @@ import { getContractProviderAssertionsPrompt } from "../../prompts/enhance-asser
|
|
|
5
5
|
import { getIntegrationAssertionsPrompt } from "../../prompts/enhance-assertions/integrationAssertionsPrompt.js";
|
|
6
6
|
import { getUIAssertionsPrompt } from "../../prompts/enhance-assertions/uiAssertionsPrompt.js";
|
|
7
7
|
import { isTestbotEnabled } from "../../utils/featureFlags.js";
|
|
8
|
+
import { renderSharedAssertionRules } from "../../prompts/enhance-assertions/sharedAssertionRules.js";
|
|
8
9
|
import { stageGeneratedPaths } from "../../utils/gitStaging.js";
|
|
9
10
|
const TOOL_NAME = "skyramp_enhance_assertions";
|
|
10
11
|
const TESTBOT_UI_CHECKS = `
|
|
@@ -12,6 +13,37 @@ const TESTBOT_UI_CHECKS = `
|
|
|
12
13
|
- If no suitable selector exists in the generated file for an assertion you need to add, go back and call \`browser_assert\` on the live page to record it with a valid selector, then re-export and regenerate.
|
|
13
14
|
- **After executing a UI test that documents a bug from \`issuesFound\`**: if it passed when you expected it to fail, the assertions are too weak — add a stronger \`expect()\` that directly targets the buggy behavior. This counts as the single allowed retry under the 2-attempt cap — do NOT re-run more than once.
|
|
14
15
|
`;
|
|
16
|
+
function buildAssertionInstructions(testFile, testType, enhanceType) {
|
|
17
|
+
if (testType === TestType.UI) {
|
|
18
|
+
let instructions = getUIAssertionsPrompt(testFile, enhanceType);
|
|
19
|
+
if (isTestbotEnabled()) {
|
|
20
|
+
instructions += TESTBOT_UI_CHECKS;
|
|
21
|
+
}
|
|
22
|
+
return instructions;
|
|
23
|
+
}
|
|
24
|
+
if (testType === TestType.CONTRACT) {
|
|
25
|
+
return getContractProviderAssertionsPrompt(testFile, enhanceType);
|
|
26
|
+
}
|
|
27
|
+
if (testType === TestType.INTEGRATION) {
|
|
28
|
+
return getIntegrationAssertionsPrompt(testFile, enhanceType);
|
|
29
|
+
}
|
|
30
|
+
throw new Error(`Unsupported testType for ${TOOL_NAME}: ${testType}`);
|
|
31
|
+
}
|
|
32
|
+
function buildAutoApplyInstructions(testFile, testType, enhanceType) {
|
|
33
|
+
const typeSpecificInstructions = buildAssertionInstructions(testFile, testType, enhanceType);
|
|
34
|
+
return [
|
|
35
|
+
`Enhance response body assertions in: \`${testFile}\``,
|
|
36
|
+
`Test type: ${testType} | Context: ${enhanceType}`,
|
|
37
|
+
``,
|
|
38
|
+
`Read the file, apply the type-specific assertion guidance below, and write the file back directly.`,
|
|
39
|
+
`Add assertions after each send_request/sendRequest status-code assertion.`,
|
|
40
|
+
`Use SDK helper: Python \`skyramp.get_response_value(response, "json.path")\`, JS \`getValue(response, "json.path")\`.`,
|
|
41
|
+
`Do NOT restructure, reformat, add comments, or change imports. Only add assertion lines.`,
|
|
42
|
+
``,
|
|
43
|
+
`Type-specific assertion guidance:`,
|
|
44
|
+
typeSpecificInstructions,
|
|
45
|
+
].join("\n");
|
|
46
|
+
}
|
|
15
47
|
const enhanceAssertionsSchema = {
|
|
16
48
|
testFile: z
|
|
17
49
|
.string()
|
|
@@ -24,6 +56,12 @@ const enhanceAssertionsSchema = {
|
|
|
24
56
|
.describe("The context of the enhancement. " +
|
|
25
57
|
"Use 'generation' after generating a new test file (applies to every test function). " +
|
|
26
58
|
"Use 'maintenance' during drift UPDATE (applies only to new or diff-affected functions)."),
|
|
59
|
+
autoApply: z
|
|
60
|
+
.boolean()
|
|
61
|
+
.default(false)
|
|
62
|
+
.describe("When true, returns a compact instruction set (10 lines) that tells the agent to " +
|
|
63
|
+
"read the test file, enhance assertions per standard rules, and write it back directly. " +
|
|
64
|
+
"When false (default), returns the full verbose instruction set."),
|
|
27
65
|
};
|
|
28
66
|
export function registerEnhanceAssertionsTool(server) {
|
|
29
67
|
server.registerTool(TOOL_NAME, {
|
|
@@ -34,26 +72,33 @@ export function registerEnhanceAssertionsTool(server) {
|
|
|
34
72
|
- After updating an existing supported test file during maintenance`,
|
|
35
73
|
inputSchema: enhanceAssertionsSchema,
|
|
36
74
|
}, async (params) => {
|
|
37
|
-
const { testFile, testType, enhanceType } = params;
|
|
75
|
+
const { testFile, testType, enhanceType, autoApply } = params;
|
|
38
76
|
// Stage so testbot includes the generated files in its output commit.
|
|
39
77
|
await stageGeneratedPaths(testFile);
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
78
|
+
if (autoApply) {
|
|
79
|
+
const compactInstructions = [
|
|
80
|
+
`Enhance response body assertions in: \`${testFile}\``,
|
|
81
|
+
`Test type: ${testType} | Context: ${enhanceType}`,
|
|
82
|
+
``,
|
|
83
|
+
`Read the file, add assertions after each send_request/sendRequest status-code assertion, write it back.`,
|
|
84
|
+
`Use SDK helper: Python \`skyramp.get_response_value(response, "json.path")\`, JS \`getValue(response, "json.path")\`.`,
|
|
85
|
+
``,
|
|
86
|
+
`Shared assertion rules (apply all that fit):`,
|
|
87
|
+
renderSharedAssertionRules(),
|
|
88
|
+
``,
|
|
89
|
+
`Do NOT restructure, reformat, add comments, or change imports. Only add assertion lines.`,
|
|
90
|
+
].join("\n");
|
|
91
|
+
const result = {
|
|
92
|
+
content: [{ type: "text", text: compactInstructions }],
|
|
93
|
+
isError: false,
|
|
94
|
+
};
|
|
95
|
+
AnalyticsService.pushMCPToolEvent(TOOL_NAME, undefined, { testFile: params.testFile, testType: params.testType, enhanceType: params.enhanceType, autoApply: Boolean(params.autoApply) }).catch(() => { });
|
|
96
|
+
return result;
|
|
56
97
|
}
|
|
98
|
+
const enhanceCtx = enhanceType;
|
|
99
|
+
const instructions = autoApply
|
|
100
|
+
? buildAutoApplyInstructions(testFile, testType, enhanceCtx)
|
|
101
|
+
: buildAssertionInstructions(testFile, testType, enhanceCtx);
|
|
57
102
|
const result = {
|
|
58
103
|
content: [
|
|
59
104
|
{
|
|
@@ -63,7 +108,12 @@ export function registerEnhanceAssertionsTool(server) {
|
|
|
63
108
|
],
|
|
64
109
|
isError: false,
|
|
65
110
|
};
|
|
66
|
-
AnalyticsService.pushMCPToolEvent(TOOL_NAME, undefined,
|
|
111
|
+
AnalyticsService.pushMCPToolEvent(TOOL_NAME, undefined, {
|
|
112
|
+
testFile: params.testFile,
|
|
113
|
+
testType: params.testType,
|
|
114
|
+
enhanceType: params.enhanceType,
|
|
115
|
+
autoApply: Boolean(params.autoApply),
|
|
116
|
+
}).catch(() => { });
|
|
67
117
|
return result;
|
|
68
118
|
});
|
|
69
119
|
}
|