@skyramp/mcp 0.2.6 → 0.2.7
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/commands/commandLibrary.d.ts +12 -0
- package/build/commands/recommendTestsAndExecuteCommand.d.ts +2 -0
- package/build/commands/testThisEndpointCommand.d.ts +2 -0
- package/build/index.d.ts +2 -0
- package/build/index.js +1 -2
- package/build/playwright/PlaywrightTraceService.d.ts +32 -0
- package/build/playwright/index.d.ts +3 -0
- package/build/playwright/registerPlaywrightTools.d.ts +8 -0
- package/build/playwright/registerPlaywrightTools.js +12 -11
- package/build/playwright/traceRecordingPrompt.d.ts +13 -0
- package/build/playwright/traceRecordingPrompt.js +3 -11
- package/build/prompts/code-reuse.d.ts +1 -0
- package/build/prompts/enhance-assertions/contractProviderAssertionsPrompt.d.ts +2 -0
- package/build/prompts/enhance-assertions/integrationAssertionsPrompt.d.ts +2 -0
- package/build/prompts/enhance-assertions/sharedAssertionRules.d.ts +15 -0
- package/build/prompts/enhance-assertions/uiAssertionsPrompt.d.ts +2 -0
- package/build/prompts/fix-error-prompt.d.ts +1 -0
- package/build/prompts/initialize-workspace/initializeWorkspacePrompt.d.ts +1 -0
- package/build/prompts/modularization/integration-test-modularization.d.ts +1 -0
- package/build/prompts/modularization/ui-test-modularization.d.ts +1 -0
- package/build/prompts/personas.d.ts +21 -0
- package/build/prompts/pom-aware-code-reuse.d.ts +1 -0
- package/build/prompts/startTraceCollectionPrompts.d.ts +2 -0
- package/build/prompts/test-maintenance/actionsInstructions.d.ts +35 -0
- package/build/prompts/test-maintenance/drift-analysis-prompt.d.ts +4 -0
- package/build/prompts/test-maintenance/driftAnalysisSections.d.ts +13 -0
- package/build/prompts/test-recommendation/analysisOutputPrompt.d.ts +84 -0
- package/build/prompts/test-recommendation/analysisOutputPrompt.test.d.ts +1 -0
- package/build/prompts/test-recommendation/analysisOutputPrompt.test.js +1 -0
- package/build/prompts/test-recommendation/diffExecutionPlan.d.ts +17 -0
- package/build/prompts/test-recommendation/diffExecutionPlan.js +7 -16
- package/build/prompts/test-recommendation/fullRepoCatalog.d.ts +7 -0
- package/build/prompts/test-recommendation/mergeEnrichedScenarios.test.d.ts +1 -0
- package/build/prompts/test-recommendation/mergeEnrichedScenarios.test.js +1 -0
- package/build/prompts/test-recommendation/promptPlan.d.ts +203 -0
- package/build/prompts/test-recommendation/promptPlan.test.d.ts +1 -0
- package/build/prompts/test-recommendation/recommendationSections.d.ts +35 -0
- package/build/prompts/test-recommendation/recommendationShared.d.ts +31 -0
- package/build/prompts/test-recommendation/registerRecommendTestsPrompt.d.ts +7 -0
- package/build/prompts/test-recommendation/scopeAssessment.d.ts +55 -0
- package/build/prompts/test-recommendation/scopeAssessment.js +2 -2
- package/build/prompts/test-recommendation/scopeAssessment.test.d.ts +1 -0
- package/build/prompts/test-recommendation/scopeAssessment.test.js +1 -0
- package/build/prompts/test-recommendation/test-recommendation-prompt.d.ts +6 -0
- package/build/prompts/test-recommendation/test-recommendation-prompt.js +4 -4
- package/build/prompts/test-recommendation/test-recommendation-prompt.test.d.ts +1 -0
- package/build/prompts/test-recommendation/test-recommendation-prompt.test.js +6 -99
- package/build/prompts/testbot/testbot-prompts.d.ts +11 -0
- package/build/prompts/testbot/testbot-prompts.js +198 -34
- package/build/prompts/testbot/testbot-prompts.test.d.ts +1 -0
- package/build/prompts/testbot/testbot-prompts.test.js +15 -73
- package/build/resources/analysisResources.d.ts +17 -0
- package/build/resources/progressResource.d.ts +2 -0
- package/build/resources/testbotResource.d.ts +2 -0
- package/build/services/AnalyticsService.d.ts +13 -0
- package/build/services/AnalyticsService.test.d.ts +1 -0
- package/build/services/AnalyticsService.test.js +86 -0
- package/build/services/ModularizationService.d.ts +11 -0
- package/build/services/ScenarioGenerationService.d.ts +37 -0
- package/build/services/ScenarioGenerationService.integration.test.d.ts +1 -0
- package/build/services/ScenarioGenerationService.integration.test.js +4 -0
- package/build/services/ScenarioGenerationService.test.d.ts +1 -0
- package/build/services/TestDiscoveryService.d.ts +128 -0
- package/build/services/TestDiscoveryService.test.d.ts +1 -0
- package/build/services/TestDiscoveryService.test.js +4 -3
- package/build/services/TestExecutionService.d.ts +46 -0
- package/build/services/TestExecutionService.test.d.ts +1 -0
- package/build/services/TestExecutionService.test.js +33 -25
- package/build/services/TestGenerationService.d.ts +56 -0
- package/build/services/TestGenerationService.test.d.ts +1 -0
- package/build/services/TestGenerationService.test.js +10 -8
- package/build/services/containerEnv.d.ts +14 -0
- package/build/tool-phase-coverage.test.d.ts +1 -0
- package/build/tool-phase-coverage.test.js +2 -0
- package/build/tool-phases.d.ts +38 -0
- package/build/tools/auth/loginTool.d.ts +2 -0
- package/build/tools/auth/logoutTool.d.ts +2 -0
- package/build/tools/code-refactor/codeReuseTool.d.ts +2 -0
- package/build/tools/code-refactor/enhanceAssertionsTool.d.ts +2 -0
- package/build/tools/code-refactor/modularizationTool.d.ts +2 -0
- package/build/tools/executeSkyrampTestTool.d.ts +2 -0
- package/build/tools/fixErrorTool.d.ts +2 -0
- package/build/tools/generate-tests/generateBatchScenarioRestTool.d.ts +45 -0
- package/build/tools/generate-tests/generateBatchScenarioRestTool.test.d.ts +1 -0
- package/build/tools/generate-tests/generateBatchScenarioRestTool.test.js +11 -9
- package/build/tools/generate-tests/generateContractRestTool.d.ts +31 -0
- package/build/tools/generate-tests/generateE2ERestTool.d.ts +13 -0
- package/build/tools/generate-tests/generateFuzzRestTool.d.ts +10 -0
- package/build/tools/generate-tests/generateIntegrationRestTool.d.ts +16 -0
- package/build/tools/generate-tests/generateLoadRestTool.d.ts +18 -0
- package/build/tools/generate-tests/generateLoadRestTool.test.d.ts +1 -0
- package/build/tools/generate-tests/generateMockRestTool.d.ts +64 -0
- package/build/tools/generate-tests/generateSmokeRestTool.d.ts +8 -0
- package/build/tools/generate-tests/generateUIRestTool.d.ts +14 -0
- package/build/tools/generate-tests/generateUIRestTool.js +1 -1
- package/build/tools/generate-tests/loadTestSchema.d.ts +39 -0
- package/build/tools/one-click/oneClickTool.d.ts +11 -0
- package/build/tools/submitReportTool.d.ts +384 -0
- package/build/tools/submitReportTool.js +144 -2
- package/build/tools/submitReportTool.test.d.ts +1 -0
- package/build/tools/submitReportTool.test.js +215 -5
- package/build/tools/test-management/actionsTool.d.ts +10 -0
- package/build/tools/test-management/analyzeChangesTool.d.ts +27 -0
- package/build/tools/test-management/analyzeChangesTool.js +44 -7
- package/build/tools/test-management/analyzeChangesTool.test.d.ts +1 -0
- package/build/tools/test-management/analyzeChangesTool.test.js +76 -39
- package/build/tools/test-management/analyzeTestHealthTool.d.ts +2 -0
- package/build/tools/test-management/index.d.ts +3 -0
- package/build/tools/test-management/index.js +0 -1
- package/build/tools/trace/resolveSaveStoragePath.d.ts +7 -0
- package/build/tools/trace/resolveSaveStoragePath.test.d.ts +1 -0
- package/build/tools/trace/resolveSessionPaths.d.ts +40 -0
- package/build/tools/trace/resolveSessionPaths.test.d.ts +1 -0
- package/build/tools/trace/sessionState.d.ts +2 -0
- package/build/tools/trace/sessionState.test.d.ts +1 -0
- package/build/tools/trace/startTraceCollectionTool.d.ts +2 -0
- package/build/tools/trace/stopTraceCollectionTool.d.ts +2 -0
- package/build/tools/workspace/initScanWorkspaceTool.d.ts +4 -0
- package/build/tools/workspace/initializeWorkspaceTool.d.ts +2 -0
- package/build/tools/workspace/initializeWorkspaceTool.test.d.ts +1 -0
- package/build/tools/workspace/initializeWorkspaceTool.test.js +134 -0
- package/build/types/OneClickCommands.d.ts +68 -0
- package/build/types/RepositoryAnalysis.d.ts +3004 -0
- package/build/types/TestAnalysis.d.ts +96 -0
- package/build/types/TestExecution.d.ts +53 -0
- package/build/types/TestRecommendation.d.ts +12 -0
- package/build/types/TestTypes.d.ts +234 -0
- package/build/utils/AnalysisStateManager.d.ts +182 -0
- package/build/utils/AnalysisStateManager.test.d.ts +1 -0
- package/build/utils/analyze-openapi.d.ts +1 -0
- package/build/utils/branchDiff.d.ts +18 -0
- package/build/utils/dartRouteExtractor.d.ts +45 -0
- package/build/utils/dartRouteExtractor.test.d.ts +1 -0
- package/build/utils/docker.d.ts +19 -0
- package/build/utils/docker.test.d.ts +1 -0
- package/build/utils/docker.test.js +10 -9
- package/build/utils/featureFlags.d.ts +37 -0
- package/build/utils/featureFlags.test.d.ts +1 -0
- package/build/utils/gitStaging.d.ts +24 -0
- package/build/utils/gitStaging.test.d.ts +1 -0
- package/build/utils/gitStaging.test.js +13 -7
- package/build/utils/httpDefaults.d.ts +10 -0
- package/build/utils/httpDefaults.test.d.ts +1 -0
- package/build/utils/initAgent.d.ts +36 -0
- package/build/utils/language-helper.d.ts +6 -0
- package/build/utils/logger.d.ts +11 -0
- package/build/utils/normalizeParams.d.ts +14 -0
- package/build/utils/normalizeSkyrampImports.d.ts +13 -0
- package/build/utils/pr-comment-parser.d.ts +31 -0
- package/build/utils/pr-comment-parser.test.d.ts +1 -0
- package/build/utils/pr-comment-parser.test.js +6 -5
- package/build/utils/projectMetadata.d.ts +15 -0
- package/build/utils/projectMetadata.test.d.ts +1 -0
- package/build/utils/proxy-terminal.d.ts +2 -0
- package/build/utils/repoScanner.d.ts +27 -0
- package/build/utils/repoScanner.test.d.ts +1 -0
- package/build/utils/routeParsers.d.ts +63 -0
- package/build/utils/routeParsers.test.d.ts +1 -0
- package/build/utils/scenarioDrafting.d.ts +71 -0
- package/build/utils/scenarioDrafting.test.d.ts +1 -0
- package/build/utils/skyrampMdContent.d.ts +5 -0
- package/build/utils/sourceRouteExtractor.d.ts +48 -0
- package/build/utils/sourceRouteExtractor.test.d.ts +1 -0
- package/build/utils/telemetry.d.ts +32 -0
- package/build/utils/telemetry.test.d.ts +1 -0
- package/build/utils/trace-parser.d.ts +32 -0
- package/build/utils/trace-parser.test.d.ts +6 -0
- package/build/utils/uiPageEnumerator.d.ts +146 -0
- package/build/utils/uiPageEnumerator.js +58 -14
- package/build/utils/uiPageEnumerator.test.d.ts +1 -0
- package/build/utils/uiPageEnumerator.test.js +223 -43
- package/build/utils/utils.d.ts +39 -0
- package/build/utils/utils.test.d.ts +1 -0
- package/build/utils/versions.d.ts +3 -0
- package/build/utils/versions.js +1 -1
- package/build/utils/workspaceAuth.d.ts +127 -0
- package/build/utils/workspaceAuth.test.d.ts +1 -0
- package/build/utils/workspaceAuth.test.js +25 -25
- package/build/workspace/index.d.ts +1 -0
- package/build/workspace/workspace.d.ts +390 -0
- package/build/workspace/workspace.test.d.ts +1 -0
- package/package.json +8 -3
- package/build/tools/test-management/uiAnalyzeChangesTool.js +0 -155
- package/build/tools/test-management/uiAnalyzeChangesTool.test.js +0 -147
|
@@ -2,6 +2,7 @@ import { z } from "zod";
|
|
|
2
2
|
import { logger } from "../../utils/logger.js";
|
|
3
3
|
import { AnalyticsService } from "../../services/AnalyticsService.js";
|
|
4
4
|
import { MAX_TESTS_TO_GENERATE, MAX_RECOMMENDATIONS, MAX_CRITICAL_TESTS, PATH_PARAM_UUID_GUIDANCE, AUTH_CONFLICT_ERROR_MSG, } from "../test-recommendation/recommendationSections.js";
|
|
5
|
+
import { buildDriftAnalysisPrompt } from "../test-maintenance/drift-analysis-prompt.js";
|
|
5
6
|
import { getTraceRecordingPromptText } from "../../playwright/traceRecordingPrompt.js";
|
|
6
7
|
import { isContractConsumerModeEnabled } from "../../utils/featureFlags.js";
|
|
7
8
|
import { resolveServiceDetailsRef } from "../../utils/utils.js";
|
|
@@ -20,9 +21,6 @@ const CONTRACT_MODE_GUIDANCE = CONSUMER_MODE_ENABLED
|
|
|
20
21
|
export function getTestbotPrompt(prTitle, prDescription, summaryOutputFile, repositoryPath, baseBranch, maxRecommendations = MAX_RECOMMENDATIONS, maxGenerate = MAX_TESTS_TO_GENERATE, _maxCritical = MAX_CRITICAL_TESTS, // Reserved — accepted for API compat but not yet wired into prompt
|
|
21
22
|
prNumber, userPrompt, services, stateOutputFile, uiCredentials, testsRepoDir) {
|
|
22
23
|
maxGenerate = Math.min(Math.max(maxGenerate, 0), maxRecommendations);
|
|
23
|
-
// TODO(SKYR-3636 follow-up): migrate Task 1 + Task 2 step bodies to PromptPlan
|
|
24
|
-
// (src/prompts/test-recommendation/promptPlan.ts) so step numbers don't have
|
|
25
|
-
// to be hand-maintained when steps are added or reordered.
|
|
26
24
|
// For follow-up requests: emit the @skyramp-testbot header + guardrails + retrieve-recommendations step.
|
|
27
25
|
// For first-run prompts: emit the full Task 1 analysis + maintenance section.
|
|
28
26
|
const task1Section = userPrompt
|
|
@@ -53,27 +51,21 @@ Use those recommendations as your baseline. Only add or remove tests that the us
|
|
|
53
51
|
|
|
54
52
|
## Task 1: Analyze & Maintain
|
|
55
53
|
|
|
56
|
-
1.
|
|
54
|
+
1. Call \`skyramp_analyze_changes\` with \`repositoryPath\`: "${repositoryPath}", \`scope\`: "branch_diff", \`topN\`: ${maxRecommendations}, \`maxGenerate\`: ${maxGenerate}${baseBranch ? `, \`baseBranch\`: "${baseBranch}"` : ""}${prNumber ? `, \`prNumber\`: ${prNumber}` : ""}${stateOutputFile ? `, \`stateOutputFile\`: "${stateOutputFile}"` : ""}${testsRepoDir ? `, \`testsRepoDir\`: "${testsRepoDir}"` : ""}.
|
|
57
55
|
|
|
58
|
-
**
|
|
56
|
+
**Follow all instructions returned by \`skyramp_analyze_changes\`** — its response opens with a **UI Blueprint Capture** section that tells you which candidate URLs to capture (and how) before you write any UI recommendation \`reasoning\`.${uiCredentials ? " If the section lists candidate URLs, log in once via the credentials in your <ui-credentials> context before navigating to them." : ""}
|
|
59
57
|
|
|
60
|
-
**Otherwise:** for each candidate URL in the response${uiCredentials ? " (after logging in via the credentials provided)" : ""}, \`browser_navigate\` to the URL, then \`browser_blueprint\` to capture. The captures stay in your tool-result history — they're the element vocabulary you'll use when writing UI recommendation \`reasoning\` fields in \`skyramp_analyze_changes\`. You do NOT need to thread them back into a tool call.
|
|
61
58
|
|
|
62
|
-
|
|
59
|
+
**Feature context check:** After capturing a blueprint per the UI Blueprint Capture instructions, cross-check whether it actually shows the changed feature. Look at the diff — what component, field, or UI element was changed? If that component only renders in a specific context (a particular collection type, a non-empty list, a specific user role, a form that only appears after a prior action), and the blueprint you captured doesn't contain it, navigate to the right context before using this blueprint for recommendations. A blueprint that doesn't show the changed feature produces recommendations that test the wrong thing — for example, recommending tests against a system collection when the PR changed behavior on custom collections. If you can't determine the right context from the diff and workspace config, note it in \`issuesFound\` and fall back to source-grounded recommendations for that URL.
|
|
63
60
|
|
|
64
|
-
2. Call \`skyramp_analyze_changes\` with \`repositoryPath\`: "${repositoryPath}", \`scope\`: "branch_diff", \`topN\`: ${maxRecommendations}, \`maxGenerate\`: ${maxGenerate}${baseBranch ? `, \`baseBranch\`: "${baseBranch}"` : ""}${prNumber ? `, \`prNumber\`: ${prNumber}` : ""}${stateOutputFile ? `, \`stateOutputFile\`: "${stateOutputFile}"` : ""}${testsRepoDir ? `, \`testsRepoDir\`: "${testsRepoDir}"` : ""}. Use the blueprints already in your context (from \`skyramp_ui_analyze_changes\`) to ground UI recommendation reasoning.
|
|
65
61
|
**If \`skyramp_analyze_changes\` returns an error:** retry once only if the error is transient (timeout, network blip, temporary unavailability) — do NOT retry for permanent errors (invalid repository path, missing required parameter, authentication failure). If it fails again, call \`skyramp_submit_report\` with a minimal valid payload: leave all test arrays empty and add the error to \`issuesFound\`. Refer to the \`skyramp_submit_report\` schema for required fields. Do NOT attempt Task 2 without a valid stateFile.
|
|
66
|
-
**If all changed files are non-application** (CI/CD, docs, lock files, config
|
|
62
|
+
**If all changed files are non-application** (CI/CD, docs, lock files, config) → skip to Task 3 (Submit Report) with empty arrays and a single \`issuesFound\` entry explaining why (same format as the zero-test path below).
|
|
67
63
|
|
|
68
|
-
|
|
64
|
+
2. **Maintain existing tests:**
|
|
69
65
|
|
|
70
|
-
|
|
66
|
+
${buildDriftAnalysisPrompt()}
|
|
71
67
|
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
c. Call \`skyramp_actions\` with \`stateFile\` (from \`skyramp_analyze_changes\` output) and apply the edits it returns.
|
|
75
|
-
|
|
76
|
-
4. **Code review:** From the \`skyramp_analyze_changes\` output and the existing test files you read for maintenance, note any logic bugs. Do NOT read additional source files just for code review — use what is already available from the analysis and test file reads. Common patterns to flag:
|
|
68
|
+
3. **Code review:** From the \`skyramp_analyze_changes\` output and the existing test files you read for maintenance, note any logic bugs. Do NOT read additional source files just for code review — use what is already available from the analysis and test file reads. Common patterns to flag:
|
|
77
69
|
- Computed fields not recalculated after mutation (e.g. \`total_amount\` unchanged after items are added/removed)
|
|
78
70
|
- Incomplete CRUD: create without cleanup, update that adds new records without removing old ones
|
|
79
71
|
- Missing input validation on new endpoints
|
|
@@ -81,15 +73,178 @@ Use those recommendations as your baseline. Only add or remove tests that the us
|
|
|
81
73
|
- Incorrect arithmetic in business logic (discount calculations, price aggregation)
|
|
82
74
|
Log each finding in \`issuesFound\` with a \`severity\` (critical/high/medium/low). These bugs should inform your test design in Task 2.
|
|
83
75
|
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
76
|
+
4. **Blueprint Citation Invariant** (UI test recommendations only). Every named UI element in your recommendation must correspond to an element actually captured in one of the blueprints you captured from the UI Blueprint Capture section of \`skyramp_analyze_changes\`. For **every** UI recommendation — both \`newTestsCreated[]\` entries (tests you generated) AND \`additionalRecommendations[]\` entries (deferred tests) with \`testType: "ui"\` — populate **four** fields: \`description\`, \`reasoning\`, \`targetElements\`, and \`pageContext\`. \`description\` and \`reasoning\` carry different roles — fill BOTH (see Field 4 below). The structured fields (\`targetElements\`, \`pageContext\`) are required on UI recs in BOTH arrays; non-UI recs (contract / integration / e2e / batch-scenario) MUST omit them.
|
|
77
|
+
|
|
78
|
+
**Field 1 — \`targetElements\`** (the elements the test targets — array, length 1+):
|
|
79
|
+
\`\`\`json
|
|
80
|
+
[
|
|
81
|
+
{
|
|
82
|
+
"role": "button",
|
|
83
|
+
"accessibleName": "Save changes",
|
|
84
|
+
"testId": "save-changes-btn",
|
|
85
|
+
"stableId": null,
|
|
86
|
+
"contextText": null,
|
|
87
|
+
"mutability": "mutable",
|
|
88
|
+
"widgetType": "native"
|
|
89
|
+
}
|
|
90
|
+
]
|
|
91
|
+
\`\`\`
|
|
92
|
+
- **One element when the test has a single dominant target** (a click, a type, a single visibility check). Most tests fall here — use a length-1 array.
|
|
93
|
+
- **Multiple elements when the test verifies several elements together** — render-state tests (heading + input + button on a form), workflow tests (click button A, assert state appears in element B), or form-fill tests (multiple inputs + submit button). Each element is its own array entry.
|
|
94
|
+
- Each element's fields are lifted verbatim from a captured blueprint element. \`role\`, \`accessibleName\` are required. \`testId\`/\`stableId\`/\`contextText\` are \`null\` when not present in the capture.
|
|
95
|
+
- \`mutability\` — copy from \`blueprint.element.mutability\`. \`'mutable'\` = behavioral-test target; \`'immutable'\` = smoke target.
|
|
96
|
+
- \`widgetType\` — copy from \`blueprint.element.widgetType\`. \`'custom'\` = JavaScript-composite control (Radix, MUI, etc.) requiring click-to-open interaction; \`'native'\` = standard HTML element.
|
|
97
|
+
- \`contextText\` — only for elements inside repeating sections (table rows, list items). Lift from \`repeatingElement.items[].contextText\`. \`null\` otherwise.
|
|
98
|
+
|
|
99
|
+
**Field 2 — \`pageContext\`** (where the test runs):
|
|
100
|
+
\`\`\`json
|
|
101
|
+
{ "url": "http://localhost:5173/orders/1", "pageHash": "10:434266447" }
|
|
102
|
+
\`\`\`
|
|
103
|
+
Lift \`url\` and \`pageHash\` from the BlueprintCapture object that fed \`targetElements\`. All entries in \`targetElements\` should be from the same page.
|
|
104
|
+
|
|
105
|
+
**Field 3 — \`reasoning\`** (one sentence — what is verified and why):
|
|
106
|
+
|
|
107
|
+
A **single sentence** (~25-50 words) that names the targeted element(s) and states what the test verifies and why it matters. There is no fixed template — write the sentence in whatever way reads naturally for the test. The constraints below are the only requirements.
|
|
108
|
+
|
|
109
|
+
- **Reference each element from \`targetElements\` by its \`accessibleName\`**. Bold each name. When the element has a \`testId\`, render it in inline code (e.g. \`save-changes-btn\`); fall back to \`stableId\` if no \`testId\`. Omit the parenthetical identifier when neither is captured. For elements inside repeating sections, include \`contextText\` parenthetically (e.g. \`(customer "Acme", total "$199.99")\`).
|
|
110
|
+
- **State what the test verifies or asserts** about those elements — the behavior, render state, business rule, or production risk.
|
|
111
|
+
- **Optionally add a "; this validates …" or "; covers …" clause** naming a formula, business rule, or source-line reference (e.g. "; this validates the \`subtotal * (1 - discountPercent/100)\` formula", "; covers the boundary clamp at EditOrderForm.tsx:42"). Skip the clause for smoke checks where there's no concrete code reference.
|
|
112
|
+
- **Voice matches which array the rec is in.** \`newTestsCreated\` uses descriptive voice ("verifies", "asserts", "documents"). \`additionalRecommendations\` uses recommendatory voice ("would verify", "should assert", "would cover"). Pick a sentence opening that matches; you do not need to start with a fixed phrase.
|
|
113
|
+
- **Multi-element recs** combine elements in one sentence using natural connectives ("and", "after clicking", "alongside") — not enumeration.
|
|
114
|
+
- Do NOT include \`logicalName\`, \`fingerprint\`, \`pageHash\`, \`xpath\`, or other internal identifiers — those leak builder internals into a user-facing report. (\`pageHash\` lives in \`pageContext\` for the verifier; never put it in prose.)
|
|
115
|
+
|
|
116
|
+
**Field 4 — \`description\`** (multi-sentence test walkthrough — REQUIRED for UI recs):
|
|
117
|
+
|
|
118
|
+
The \`description\` field complements \`reasoning\`. While \`reasoning\` is one sentence about what the test verifies and why, \`description\` is **2-4 sentences of free-form prose** describing the test as a walkthrough — the page navigated to, the actions taken, the assertions made, the data values used. Reads like documentation for whoever implements the test.
|
|
119
|
+
|
|
120
|
+
- For \`newTestsCreated\`: describe what the test does step by step. Example: "Navigates to /orders/1, opens the Edit Order form, enters discount=20%, submits, and asserts the real-time total updates to $799.99 before the PUT call."
|
|
121
|
+
- For \`additionalRecommendations\`: describe what the recommended test would do. Example: "Would navigate to a cancelled order's detail page and assert the Edit Order button is not rendered, enforcing the conditional guard added in OrderDetail.tsx."
|
|
122
|
+
- **\`description\` is NOT a duplicate of \`reasoning\`.** Keep them complementary: \`description\` = what the test does (walkthrough), \`reasoning\` = what's verified + why (one sentence).
|
|
123
|
+
- Same jargon-exclusion rules apply (no \`logicalName\` / \`pageHash\` / etc.).
|
|
124
|
+
- Same fallback rules apply: when no blueprint is available, prefix \`description\` and \`reasoning\` with \`[no-blueprint-data]\` and use page/feature-level prose.
|
|
125
|
+
|
|
126
|
+
**Examples (showing the full bundle — copy the structure, not the exact wording):**
|
|
127
|
+
|
|
128
|
+
*Single-element generated test (descriptive voice, with rationale clause):*
|
|
129
|
+
\`\`\`json
|
|
130
|
+
{
|
|
131
|
+
"testType": "ui",
|
|
132
|
+
"description": "Navigates to /orders/1, opens the Edit Order form, enters discount=150, submits, and asserts the validation error 'Discount must be ≤ 100' appears and the form does not close. Documents the boundary-clamp guard in EditOrderForm.tsx.",
|
|
133
|
+
"targetElements": [
|
|
134
|
+
{
|
|
135
|
+
"role": "button", "accessibleName": "Save changes",
|
|
136
|
+
"testId": "save-changes-btn", "stableId": null,
|
|
137
|
+
"contextText": null, "mutability": "mutable", "widgetType": "native"
|
|
138
|
+
}
|
|
139
|
+
],
|
|
140
|
+
"pageContext": {
|
|
141
|
+
"url": "http://localhost:5173/orders/1",
|
|
142
|
+
"pageHash": "10:434266447"
|
|
143
|
+
},
|
|
144
|
+
"reasoning": "Verifies the **Save changes** button (\`save-changes-btn\`) shows a validation error and prevents form close when discount > 100; this validates the \`Math.min(100, Math.max(0, value))\` clamp at EditOrderForm.tsx:42."
|
|
145
|
+
}
|
|
146
|
+
\`\`\`
|
|
147
|
+
|
|
148
|
+
*Multi-element generated test (render-state, descriptive voice):*
|
|
149
|
+
\`\`\`json
|
|
150
|
+
{
|
|
151
|
+
"testType": "ui",
|
|
152
|
+
"description": "Navigates to /orders/1, clicks Edit Order, and asserts both the 'Edit Order' heading and the Discount (%) input render with discount pre-filled to 0. Smoke check before any user interaction.",
|
|
153
|
+
"targetElements": [
|
|
154
|
+
{
|
|
155
|
+
"role": "heading", "accessibleName": "Edit Order",
|
|
156
|
+
"testId": "edit-order-heading", "stableId": null,
|
|
157
|
+
"contextText": null, "mutability": "immutable", "widgetType": "native"
|
|
158
|
+
},
|
|
159
|
+
{
|
|
160
|
+
"role": "spinbutton", "accessibleName": "Discount (%)",
|
|
161
|
+
"testId": "edit-order-input-discount", "stableId": null,
|
|
162
|
+
"contextText": null, "mutability": "mutable", "widgetType": "native"
|
|
163
|
+
}
|
|
164
|
+
],
|
|
165
|
+
"pageContext": {
|
|
166
|
+
"url": "http://localhost:5173/orders/1",
|
|
167
|
+
"pageHash": "13:-684516288"
|
|
168
|
+
},
|
|
169
|
+
"reasoning": "Asserts the **Edit Order** heading (\`edit-order-heading\`) and **Discount (%)** input (\`edit-order-input-discount\`) render with discount pre-filled to 0 on form mount; covers the form-mount default-value contract."
|
|
170
|
+
}
|
|
171
|
+
\`\`\`
|
|
172
|
+
|
|
173
|
+
*Negative test (asserts element is NOT rendered), recommendatory voice:*
|
|
174
|
+
\`\`\`json
|
|
175
|
+
{
|
|
176
|
+
"testType": "ui",
|
|
177
|
+
"description": "Would navigate to a cancelled order's detail page and assert the Edit Order button is not rendered. Enforces the conditional-render guard added in OrderDetail.tsx.",
|
|
178
|
+
"targetElements": [
|
|
179
|
+
{
|
|
180
|
+
"role": "button", "accessibleName": "Edit Order",
|
|
181
|
+
"testId": "edit-order-btn", "stableId": null,
|
|
182
|
+
"contextText": null, "mutability": "mutable", "widgetType": "native"
|
|
183
|
+
}
|
|
184
|
+
],
|
|
185
|
+
"pageContext": {
|
|
186
|
+
"url": "http://localhost:5173/orders/cancelled-99",
|
|
187
|
+
"pageHash": "9:712044820"
|
|
188
|
+
},
|
|
189
|
+
"reasoning": "Would assert the **Edit Order** button (\`edit-order-btn\`) is not rendered on cancelled orders; enforces the conditional-render guard added in OrderDetail.tsx:118."
|
|
190
|
+
}
|
|
191
|
+
\`\`\`
|
|
192
|
+
(For negative tests, ground \`targetElements\` against a captured page where the element DOES render — so the verifier can confirm the citation is real.)
|
|
193
|
+
|
|
194
|
+
*Page-level / lifecycle test (no single dominant element), recommendatory voice:*
|
|
195
|
+
\`\`\`json
|
|
196
|
+
{
|
|
197
|
+
"testType": "ui",
|
|
198
|
+
"description": "Would walk through create → edit → cancel of an order, asserting the Order details heading reflects each state transition (Pending → Editing → Cancelled). Covers the OrderStatus state machine added in this PR.",
|
|
199
|
+
"targetElements": [
|
|
200
|
+
{
|
|
201
|
+
"role": "heading", "accessibleName": "Order details",
|
|
202
|
+
"testId": null, "stableId": null, "contextText": null,
|
|
203
|
+
"mutability": "immutable", "widgetType": "native"
|
|
204
|
+
}
|
|
205
|
+
],
|
|
206
|
+
"pageContext": {
|
|
207
|
+
"url": "http://localhost:5173/orders/1",
|
|
208
|
+
"pageHash": "11:200115447"
|
|
209
|
+
},
|
|
210
|
+
"reasoning": "Would walk the create-edit-cancel order lifecycle and assert the **Order details** heading reflects each state transition; covers the OrderStatus state machine added in this PR."
|
|
211
|
+
}
|
|
212
|
+
\`\`\`
|
|
213
|
+
(When there's no single focus, anchor on the page heading or the most stable on-page element.)
|
|
214
|
+
|
|
215
|
+
*Single-element additional recommendation (recommendatory voice):*
|
|
216
|
+
\`\`\`json
|
|
217
|
+
{
|
|
218
|
+
"testType": "ui",
|
|
219
|
+
"description": "Would navigate to /admin/notifications when the inbox is empty and assert the Notifications heading renders alongside the empty-state message. Smoke check that the page handles the zero-rows case.",
|
|
220
|
+
"targetElements": [
|
|
221
|
+
{
|
|
222
|
+
"role": "heading", "accessibleName": "Notifications",
|
|
223
|
+
"testId": null, "stableId": null, "contextText": null,
|
|
224
|
+
"mutability": "immutable", "widgetType": "native"
|
|
225
|
+
}
|
|
226
|
+
],
|
|
227
|
+
"pageContext": {
|
|
228
|
+
"url": "http://localhost:5173/admin/notifications",
|
|
229
|
+
"pageHash": "8:992103445"
|
|
230
|
+
},
|
|
231
|
+
"reasoning": "Would assert the **Notifications** heading renders alongside the empty-state message when the inbox has zero rows; covers the empty-state render path added in NotificationsPage.tsx:31."
|
|
232
|
+
}
|
|
233
|
+
\`\`\`
|
|
234
|
+
|
|
235
|
+
**Self-check before submitting (per UI rec, in both \`newTestsCreated\` and \`additionalRecommendations\`):**
|
|
236
|
+
- **Both \`description\` AND \`reasoning\` are populated.** \`description\` is a 2-4 sentence walkthrough; \`reasoning\` is one sentence about what's verified + why. They must not duplicate each other.
|
|
237
|
+
- Every entry in \`targetElements\` must appear verbatim in a captured blueprint element (matched on \`accessibleName\` + \`role\`).
|
|
238
|
+
- Every element name appearing in \`reasoning\` must match an entry's \`accessibleName\` exactly. Every backticked identifier in \`reasoning\` must come from a \`testId\` or \`stableId\` of an entry.
|
|
239
|
+
- **Voice matches the array:** \`newTestsCreated\` uses descriptive voice ("verifies", "asserts", "documents"). \`additionalRecommendations\` uses recommendatory voice ("would verify", "should assert", "would cover").
|
|
240
|
+
- \`pageContext.url\` must equal the URL of the BlueprintCapture you lifted \`targetElements\` from.
|
|
241
|
+
- Never mix two elements' fields in one \`targetElements\` entry — each entry is one captured element.
|
|
242
|
+
- No internal jargon in \`reasoning\` or \`description\`: no \`logicalName\`, \`fingerprint\`, \`pageHash\`, \`xpath\`.
|
|
243
|
+
- If any check fails, re-capture and verify, or drop that recommendation.
|
|
244
|
+
|
|
245
|
+
**Non-UI entries (contract / integration / e2e / batch-scenario) are unaffected.** Use their pre-existing reasoning formats. Do NOT add \`targetElements\` or \`pageContext\` to non-UI entries — the schema rejects them.
|
|
246
|
+
|
|
247
|
+
**No upstream captures available?** Set \`targetElements\` to \`null\`, omit \`pageContext\`, and prefix \`description\` and \`reasoning\` with \`[no-blueprint-data]\`. Use page/feature-level prose; don't cite specific element names without grounding. Apply the marker per entry, not per PR — affected recs only. Log capture failures in \`issuesFound\` (one info-severity entry per failure mode, naming counts). Don't pre-emptively fall back without attempting capture first. Non-UI work is unaffected.
|
|
93
248
|
|
|
94
249
|
---`;
|
|
95
250
|
const serviceContext = services?.length ? buildServiceContext(services) : '';
|
|
@@ -122,7 +277,7 @@ ${userPrompt ? "Generate only the tests that the user requested from the Additio
|
|
|
122
277
|
- **MANDATORY — use the pre-ranked GENERATE list as-is**: The Execution Plan's GENERATE section governs ADD actions. You MUST generate exactly those scenarios in the exact order listed. Do NOT substitute, rename, or replace a GENERATE item. If parameter grounding uncovers a distinct bug-catching scenario not already in the GENERATE or ADDITIONAL list, generate it after all planned GENERATE items are complete and report it in \`newTestsCreated\` — this is an additional test driven by source-code analysis and does not count against the GENERATE budget.
|
|
123
278
|
- Scenario JSON files are always new files — always generate them for new methods. Every generated scenario JSON must have a corresponding new integration test generated from it via \`skyramp_integration_test_generation\`.
|
|
124
279
|
- Covered-resource handling (aligns with Execution Plan Step 0): When a GENERATE item targets a resource that already has an existing test file covering the same endpoint:
|
|
125
|
-
- If the existing test source is \`[external]\`, skip the resource entirely — the external test already provides coverage. Do NOT
|
|
280
|
+
- If the existing test source is \`[external]\`, skip the resource entirely — the external test already provides coverage. Do NOT UPDATE, REGENERATE, or DELETE external tests.
|
|
126
281
|
- If the existing test is tagged \`[skyramp]\`, apply type-specific rules:
|
|
127
282
|
- Contract tests: UPDATE the existing Skyramp test file (add the new method's test cases). A new test case is a new test even if the file already exists — report in \`newTestsCreated\` and count toward the budget.
|
|
128
283
|
- Integration/scenario tests: Always generate as a new file via the scenario pipeline (\`skyramp_batch_scenario_test_generation\` → \`skyramp_integration_test_generation\`), even if an existing integration test covers the same resource. A new multi-step scenario (e.g. create → PATCH → verify recalculation) is a distinct test file. Report in \`newTestsCreated\` and count toward the budget.
|
|
@@ -139,7 +294,6 @@ ${userPrompt ? "Generate only the tests that the user requested from the Additio
|
|
|
139
294
|
2. If no production file imports, re-exports, or renders it, the component has no DOM node in the running app → unintegrated.
|
|
140
295
|
3. **Exception**: if the same PR also adds a route/page file (e.g. under Next.js \`pages/\` or \`app/\`) that imports the component, the route IS the integration point — test through it.
|
|
141
296
|
**Never** apply the unintegrated heuristic to framework route/entrypoint files themselves — those are always reachable by convention.
|
|
142
|
-
- **(c) Cosmetic-only frontend change** — the frontend files in the diff are purely cosmetic with no observable rendering or interaction change (e.g. a \`.css\`/\`.scss\` reformat: property reordering, comment/whitespace edits, \`0px\`→\`0\`). \`uiContext.changedFrontendFiles\` being non-empty does NOT override this — that signal only means a frontend file changed, not that behavior changed. Take the zero-test abstention path in Task 3; do NOT record a trace just to satisfy the mandate.
|
|
143
297
|
**Never** generate tests for unrelated pages as a substitute for an unintegrated component.
|
|
144
298
|
This rule takes priority over generating additional backend-only tests.
|
|
145
299
|
- **Always generate a test for critical bugs, even if it will fail.** When a GENERATE-tagged item targets a page or endpoint with a known bug, do NOT skip it because you expect the test to fail — a failing test that documents a bug is more valuable than a text-only description. This applies within the existing GENERATE budget; do not add extra tests beyond the plan.
|
|
@@ -226,6 +380,7 @@ ${CONTRACT_MODE_GUIDANCE}
|
|
|
226
380
|
- \`skyramp_export_zip\` outputPath: \`${repositoryPath}/.skyramp/<test_name>_trace.zip\`
|
|
227
381
|
- \`skyramp_ui_test_generation\`: set \`modularizeCode: false\`
|
|
228
382
|
- **\`browser_assert\` — MANDATORY**: at least one per page navigated. Call multiple assertions in the same tool call batch when checking independent elements. If you navigate to 2 pages, assert on both. Each assertion should verify a business outcome (state change, computed value, error condition) — not just that an element is visible.
|
|
383
|
+
- **Wait for stable state before the second capture**: After performing an action that affects computed fields (filling a discount, submitting a form, adding an item), check the current page state before calling the second \`browser_blueprint\` (the capture after the action). If a computed field — total, price, count, derived text — still shows its initial empty or zero value (e.g. \`$0.00\`, \`0\`, \`Loading...\`, empty string), that means async data hasn't finished loading yet. Use \`browser_wait_for\` to wait up to 10 seconds for the field to update to a real value (for example, wait for the total to show a non-zero amount like \`$799.99\` instead of \`$0.00\`). Once the field shows a real value, THEN call the second \`browser_blueprint\` to capture stable state. If after 10 seconds the field still hasn't updated, skip the assertion on that field — don't capture and assert a value that hasn't loaded.
|
|
229
384
|
If \`browser_navigate\` fails (app not running / connection refused), move to \`additionalRecommendations\` with the failure reason.
|
|
230
385
|
Record at most 2-3 UI traces per run to stay within tool call budget. Quality over quantity: 1 great test is better than 3 mediocre ones — do not pad to reach the count.
|
|
231
386
|
**Strategic assertions** — key checkpoints only, 3 to 5 per test:
|
|
@@ -238,9 +393,9 @@ ${CONTRACT_MODE_GUIDANCE}
|
|
|
238
393
|
|
|
239
394
|
**Capture-act-capture (applies only when recording a UI trace):**
|
|
240
395
|
|
|
241
|
-
**Skip this entire section if \`uiContext\` was absent or \`changedFrontendFiles\` was empty in the \`
|
|
396
|
+
**Skip this entire section if \`uiContext\` was absent or \`changedFrontendFiles\` was empty in the \`skyramp_analyze_changes\` response** (backend-only PR). The capture-act-capture pattern is for UI trace recording only — there's no UI trace to record on a backend-only PR. Continue to the non-UI test-type instructions below.
|
|
242
397
|
|
|
243
|
-
**Reminder — the UI test priority rule above still applies.** If the diff contains frontend/UI changes, you still MUST attempt to generate at least one UI test. Capture-act-capture is **how** you record that test, not **whether** you record one — do not substitute UI recommendations for actually recording a trace. UI recommendation reasoning was already grounded in the
|
|
398
|
+
**Reminder — the UI test priority rule above still applies.** If the diff contains frontend/UI changes, you still MUST attempt to generate at least one UI test. Capture-act-capture is **how** you record that test, not **whether** you record one — do not substitute UI recommendations for actually recording a trace. UI recommendation reasoning was already grounded in the blueprints you captured from the UI Blueprint Capture section of \`skyramp_analyze_changes\`; Task 2's capture-act-capture is for the trace's own assertions, not for retroactively rewriting recommendation reasoning.
|
|
244
399
|
|
|
245
400
|
This pattern produces delta-derived assertions from blueprint diffs. Diff-derived assertions catch state changes more reliably than author-inference — the diff tells you what actually changed on the page so the assertion is grounded in observable state, not in guessing what "success" looks like.
|
|
246
401
|
|
|
@@ -254,15 +409,23 @@ ${CONTRACT_MODE_GUIDANCE}
|
|
|
254
409
|
|
|
255
410
|
1. **Before** the action: \`browser_blueprint\`. Identify the semantic target by \`role\`, \`accessibleName\`, and \`stableId\`/\`testId\`.
|
|
256
411
|
|
|
257
|
-
2. If the target's \`widgetType\` is \`"custom"\` or \`"unknown"
|
|
412
|
+
2. If the target's \`widgetType\` is \`"custom"\` or \`"unknown"\`, it is a JavaScript-composite control (e.g. a Radix/MUI combobox, a date picker, a custom multi-select) that does not behave like a native HTML element. Do NOT call \`browser_fill\` or \`browser_select_option\` directly on it. Instead: click the trigger element first, use \`browser_wait_for\` to wait for the overlay/dropdown to appear, then interact with its contents. Use \`browser_snapshot\` to inspect what appeared before choosing what to click next.
|
|
258
413
|
|
|
259
414
|
3. Execute the action via \`browser_click\` / \`browser_type\` / \`browser_navigate\`. The \`ref\` comes from \`browser_snapshot\` as today.
|
|
260
415
|
|
|
261
416
|
4. **After** the action: \`browser_blueprint\` again. The response shape depends on whether the action navigated:
|
|
262
|
-
- **Same URL (modal/tab/in-place mutation):** \`{ isFullCapture: false, pageHash, previousPageHash, delta, possibleAssertions }\`. The \`delta\` field contains \`elementsAdded\`, \`elementsRemoved\`, \`textChanges\`, \`repeatingCountChanges\`. The \`possibleAssertions\` field is a mechanical translation of those entries into Playwright \`expect(...)\` candidates — see step 5.
|
|
263
|
-
- **Navigated to a new URL** (e.g. router transition, link click, programmatic \`browser_navigate\`): \`{ isFullCapture: true, pageHash, blueprint }\` — a fresh full capture of the new page. No \`possibleAssertions\` here (no delta to translate).
|
|
417
|
+
- **Same URL (modal/tab/in-place mutation):** \`{ isFullCapture: false, pageHash, previousPageHash, delta, possibleAssertions }\`. The \`delta\` field contains \`elementsAdded\`, \`elementsRemoved\`, \`textChanges\`, \`repeatingCountChanges\`. The \`possibleAssertions\` field is a mechanical translation of those entries into Playwright \`expect(...)\` candidates — see step 5. An empty delta (all arrays empty) is itself a meaningful signal: the action did not change observable DOM (e.g. a silent failure the test should catch).
|
|
418
|
+
- **Navigated to a new URL** (e.g. router transition, link click, programmatic \`browser_navigate\`): \`{ isFullCapture: true, pageHash, blueprint }\` — a fresh full capture of the new page. No \`possibleAssertions\` here (no delta to translate). Search the new blueprint for the elements your assertion will target.
|
|
419
|
+
|
|
420
|
+
5. **The second \`browser_blueprint\` response (the capture after the action) includes a \`possibleAssertions[]\` array — mechanical translations of delta entries into ready-to-use Playwright \`expect(...)\` candidates.** Each entry has \`{ code, rationale, tier }\`. Use tier to drive your assertion choices:
|
|
421
|
+
|
|
422
|
+
- **HIGH** — always assert on these. HIGH candidates translate state-observable changes: text content that updated (\`toHaveText\`), URL transitions (\`toHaveURL\`), count changes (\`toHaveCount\`). If a HIGH-tier candidate exists after an action, it is the primary assertion for that action. (If you followed the stable-state rule above and waited for real data before capturing, HIGH candidates will already contain real values — not loading state.)
|
|
423
|
+
- **MEDIUM** — use as supplementary assertions. MEDIUM candidates translate structural changes: an element appeared (\`toBeVisible\`) or disappeared (\`not.toBeVisible\`) after the action. Useful alongside HIGH assertions but insufficient alone for state-changing actions.
|
|
424
|
+
- **LOW** — treat as context only. LOW candidates are incidental visibility checks on elements that happened to be on-page. Do not use LOW candidates as the sole assertion on a state-changing action.
|
|
425
|
+
|
|
426
|
+
**If no HIGH-tier candidate exists after a state-changing action** (form submit, button click that mutates data), write a targeted assertion yourself — look in the second blueprint capture for computed values, status fields, or derived text that changed. One well-targeted \`toHaveText\` or \`toHaveValue\` beats five \`toBeVisible\` checks.
|
|
264
427
|
|
|
265
|
-
|
|
428
|
+
**The pre-existing rule still applies:** at least one \`browser_assert\` per page navigated, verifying a business outcome — not just that an element is visible.
|
|
266
429
|
|
|
267
430
|
**The Blueprint Citation Invariant applies during recording too.** Every assertion you emit cites element names — those names must come from blueprint captures, not invention. For N user-intent-level actions, the reference target is N+1 \`browser_blueprint\` calls (the first returns full, the rest return deltas). Traces that follow the pattern produce assertions grounded in observable state changes; traces that skip captures fall back to author-inferred assertions and risk citing names that don't exist in the rendered DOM.
|
|
268
431
|
|
|
@@ -299,7 +462,7 @@ Do NOT use \`page.waitForTimeout()\` with fixed delays. Do NOT retry more than o
|
|
|
299
462
|
**After generation, you MUST do exactly these steps — nothing more, nothing less:**
|
|
300
463
|
1. **[MANDATORY] After \`skyramp_integration_test_generation\`**: Call \`skyramp_enhance_assertions\` with \`testFile\` set to the absolute path of the generated integration test file, \`testType: "integration"\`, and \`enhanceType: "generation"\`. Apply every instruction returned to that file.
|
|
301
464
|
2. **[MANDATORY] After \`skyramp_contract_test_generation\` with \`providerMode\`**: Call \`skyramp_enhance_assertions\` with \`testFile\` set to the absolute path of the generated provider contract test file, \`testType: "contract"\`, and \`enhanceType: "generation"\`. Apply every instruction returned to that file.
|
|
302
|
-
3. **[MANDATORY] After \`skyramp_ui_test_generation\`**: Call \`skyramp_enhance_assertions\` with \`testFile\` set to the absolute path of the generated UI test file, \`testType: "ui"\`, and \`enhanceType: "generation"\`. Apply every instruction returned to that file.
|
|
465
|
+
3. **[MANDATORY] After \`skyramp_ui_test_generation\`**: Call \`skyramp_enhance_assertions\` with \`testFile\` set to the absolute path of the generated UI test file, \`testType: "ui"\`, and \`enhanceType: "generation"\`. Apply every instruction returned to that file. The HIGH-tier \`possibleAssertions\` from your second \`browser_blueprint\` captures (after each action) during trace recording are in your context — when the enhance instructions ask you to add assertions for state-changing actions, use those grounded candidates first (they contain exact computed values from the DOM delta, e.g. \`toHaveText('Total: $899.98')\`). Only fall back to deriving values from the test file or source code when no HIGH-tier candidate covers the action.
|
|
303
466
|
4. **Wait**: Do NOT proceed to test execution until steps 1–3 are complete and the verification checklist in the \`skyramp_enhance_assertions\` tool result has been validated for EVERY generated test file.
|
|
304
467
|
Do not make any changes other than the assertion enhancements described above. For example: do not modify auth headers, cookies, tokens, env vars, or imports that the generation tool already set correctly — those are correct by construction and changing them breaks auth or execution.
|
|
305
468
|
|
|
@@ -336,6 +499,7 @@ Call \`skyramp_submit_report\` with \`summaryOutputFile\`: "${summaryOutputFile}
|
|
|
336
499
|
- **additionalRecommendations**: AT MOST ${maxRecommendations - maxGenerate} items.
|
|
337
500
|
- For \`testType: "contract"\` entries: **\`primaryEndpoint\` is required** (e.g. \`"GET /api/v1/users/{user_id}"\`). The tool will reject the submission without it — do not omit it or you will be forced to resubmit.
|
|
338
501
|
- For \`testType: "integration"\` or \`"e2e"\` entries: omit \`primaryEndpoint\` — use \`description\` to list the endpoints involved instead.
|
|
502
|
+
- **testMaintenance**: Use \`[]\` **only** if no existing Skyramp tests were found in the repository. If existing tests were found (any score), include one entry per test. Set \`action\` to the exact drift action you chose from the Action Decision Matrix (\`UPDATE\`, \`REGENERATE\`, \`DELETE\`, \`VERIFY\`, or \`IGNORE\`). For UPDATE/REGENERATE/DELETE tests that were modified and executed, populate all fields from real before/after execution results. For VERIFY/IGNORE tests (not modified), derive \`beforeStatus\` from the \`skyramp_analyze_test_health\` health score (typically \`"Pass"\` if drift score is 0 and no health issues were flagged), set \`afterStatus\` to \`"Skipped"\`, and use \`afterDetails\` to explain why (e.g. "IGNORE: drift score 0 — endpoint not modified in this PR"). Do **not** add entries for tests that were not returned by the health analysis.
|
|
339
503
|
|
|
340
504
|
---
|
|
341
505
|
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
jest
|
|
1
|
+
import { jest } from "@jest/globals";
|
|
2
|
+
jest.unstable_mockModule("../../workspace/workspace.js", () => ({
|
|
2
3
|
WorkspaceConfigManager: jest.fn(),
|
|
3
4
|
}));
|
|
4
|
-
jest.
|
|
5
|
+
jest.unstable_mockModule("../../services/AnalyticsService.js", () => ({
|
|
5
6
|
AnalyticsService: { pushMCPToolEvent: jest.fn() },
|
|
6
7
|
}));
|
|
7
|
-
jest.
|
|
8
|
+
jest.unstable_mockModule("../../playwright/traceRecordingPrompt.js", () => ({
|
|
8
9
|
getTraceRecordingPromptText: () => "",
|
|
9
10
|
}));
|
|
10
|
-
|
|
11
|
+
const { getTestbotPrompt, buildWorkspaceRecoveryPrefix } = await import("./testbot-prompts.js");
|
|
11
12
|
// Minimal args to invoke getTestbotPrompt — only services matter for these tests
|
|
12
13
|
const baseArgs = {
|
|
13
14
|
prTitle: "Test PR",
|
|
@@ -216,13 +217,11 @@ describe("drift analysis — runtime tool call (step 3)", () => {
|
|
|
216
217
|
const prompt = basePrompt();
|
|
217
218
|
expect(prompt).toContain("skyramp_actions");
|
|
218
219
|
});
|
|
219
|
-
it("
|
|
220
|
+
it("skyramp_analyze_test_health is referenced in the prompt", () => {
|
|
221
|
+
// After the unified maintenance refactor, analyze_test_health is referenced
|
|
222
|
+
// in the testMaintenance submission guidance rather than as an explicit step.
|
|
220
223
|
const prompt = basePrompt();
|
|
221
|
-
|
|
222
|
-
const healthPos = prompt.indexOf("skyramp_analyze_test_health");
|
|
223
|
-
const task2Pos = prompt.indexOf("## Task 2");
|
|
224
|
-
expect(healthPos).toBeGreaterThan(task1Pos);
|
|
225
|
-
expect(healthPos).toBeLessThan(task2Pos);
|
|
224
|
+
expect(prompt).toContain("skyramp_analyze_test_health");
|
|
226
225
|
});
|
|
227
226
|
it("does not contain the build-time embedded drift_analysis_rules content (Action Decision Tree)", () => {
|
|
228
227
|
// The rules are now fetched at runtime via skyramp_analyze_test_health —
|
|
@@ -237,57 +236,7 @@ describe("drift analysis — runtime tool call (step 3)", () => {
|
|
|
237
236
|
expect(prompt).not.toContain("You are acting as a Skyramp Integration Architect");
|
|
238
237
|
});
|
|
239
238
|
});
|
|
240
|
-
describe("UI grounding via Task 2 capture-act-capture", () => {
|
|
241
|
-
it("surfaces uiContext as guidance, not a contract", () => {
|
|
242
|
-
const prompt = getTestbotPrompt(baseArgs.prTitle, baseArgs.prDescription, baseArgs.summaryOutputFile, baseArgs.repositoryPath);
|
|
243
|
-
// uiContext fields are explained inline so the agent knows what to do with
|
|
244
|
-
// them. Step 1 provides candidate URLs but gives fallback instructions
|
|
245
|
-
// ("navigate from the workspace baseUrl and explore") for 404s/redirects,
|
|
246
|
-
// treating candidates as guidance not a rigid contract.
|
|
247
|
-
expect(prompt).toContain("uiContext");
|
|
248
|
-
expect(prompt).toContain("candidateUiPages");
|
|
249
|
-
expect(prompt).toContain("changedFrontendFiles");
|
|
250
|
-
expect(prompt).toMatch(/navigate from the workspace baseUrl and explore/i);
|
|
251
|
-
});
|
|
252
|
-
it("step 5 enforces Blueprint Citation Invariant in natural prose", () => {
|
|
253
|
-
const prompt = getTestbotPrompt(baseArgs.prTitle, baseArgs.prDescription, baseArgs.summaryOutputFile, baseArgs.repositoryPath);
|
|
254
|
-
// Step 5 is the citation-invariant guardrail, not a "fill in tuples"
|
|
255
|
-
// post-processing step (slice 4 cleanup: recs are grounded upstream).
|
|
256
|
-
expect(prompt).toContain("Blueprint Citation Invariant");
|
|
257
|
-
// Reasoning must be natural prose, NOT internal-identifier syntax.
|
|
258
|
-
expect(prompt).toMatch(/natural prose/i);
|
|
259
|
-
expect(prompt).toMatch(/internal-identifier syntax/i);
|
|
260
|
-
});
|
|
261
|
-
it("Task 2 no longer instructs the agent to fill in tuples post-hoc", () => {
|
|
262
|
-
const prompt = getTestbotPrompt(baseArgs.prTitle, baseArgs.prDescription, baseArgs.summaryOutputFile, baseArgs.repositoryPath);
|
|
263
|
-
// After slice 4 cleanup: Task 2 captures are for trace recording's own
|
|
264
|
-
// assertions, not for retroactively rewriting recommendation reasoning.
|
|
265
|
-
// The phrase "fill in tuples" must NOT appear anywhere in the prompt.
|
|
266
|
-
expect(prompt).not.toMatch(/fill in tuples/i);
|
|
267
|
-
expect(prompt).not.toMatch(/return to step 5 and fill/i);
|
|
268
|
-
});
|
|
269
|
-
it("Task 2 step 5 mentions possibleAssertions as available, NOT as required (slice 5.5 softening)", () => {
|
|
270
|
-
const prompt = getTestbotPrompt(baseArgs.prTitle, baseArgs.prDescription, baseArgs.summaryOutputFile, baseArgs.repositoryPath);
|
|
271
|
-
// Slice 5: AFTER-action browser_blueprint response includes
|
|
272
|
-
// possibleAssertions[] — mechanically translated candidates.
|
|
273
|
-
expect(prompt).toContain("possibleAssertions");
|
|
274
|
-
// Slice 5.5: prompt explicitly tells the agent NOT to feel obligated.
|
|
275
|
-
// Two P09 runs with the prior "emit at least one" directive showed the
|
|
276
|
-
// agent over-using shallow visibility assertions at the expense of
|
|
277
|
-
// integration-test depth. The softened version says: read them, use
|
|
278
|
-
// when they happen to match what you'd write anyway, ignore otherwise.
|
|
279
|
-
expect(prompt).toMatch(/do not feel obligated/i);
|
|
280
|
-
expect(prompt).toMatch(/biased toward visibility/i);
|
|
281
|
-
// The candidate format is still documented.
|
|
282
|
-
expect(prompt).toMatch(/\bcode\b.*\brationale\b.*\btier\b/i);
|
|
283
|
-
// The pre-existing "at least one browser_assert per page navigated"
|
|
284
|
-
// rule should be preserved (it's about meaningful business-outcome
|
|
285
|
-
// assertions, not about possibleAssertions).
|
|
286
|
-
expect(prompt).toMatch(/at least one .browser_assert. per page navigated/i);
|
|
287
|
-
});
|
|
288
|
-
});
|
|
289
239
|
describe("buildWorkspaceRecoveryPrefix", () => {
|
|
290
|
-
const { buildWorkspaceRecoveryPrefix } = require("./testbot-prompts.js");
|
|
291
240
|
it("includes repositoryPath in both init_scan and init_workspace instructions", () => {
|
|
292
241
|
const prefix = buildWorkspaceRecoveryPrefix("/home/user/repo");
|
|
293
242
|
expect(prefix).toContain('skyramp_init_scan with workspacePath "/home/user/repo"');
|
|
@@ -348,20 +297,13 @@ describe("testsRepoDir in getTestbotPrompt", () => {
|
|
|
348
297
|
});
|
|
349
298
|
});
|
|
350
299
|
describe("testbot prompt blueprint-grounded recommendations (slice 4)", () => {
|
|
351
|
-
it("
|
|
352
|
-
const prompt = getTestbotPrompt(baseArgs.prTitle, baseArgs.prDescription, baseArgs.summaryOutputFile, baseArgs.repositoryPath);
|
|
353
|
-
const uiacIdx = prompt.indexOf("skyramp_ui_analyze_changes");
|
|
354
|
-
const acIdx = prompt.indexOf("skyramp_analyze_changes");
|
|
355
|
-
expect(uiacIdx).toBeGreaterThan(-1);
|
|
356
|
-
expect(acIdx).toBeGreaterThan(uiacIdx);
|
|
357
|
-
});
|
|
358
|
-
it("Task 1 step 1 instructs the agent to capture blueprints (without threading them through a param)", () => {
|
|
300
|
+
it("uses a single skyramp_analyze_changes call (no separate pre-flight tool, no blueprint threading)", () => {
|
|
359
301
|
const prompt = getTestbotPrompt(baseArgs.prTitle, baseArgs.prDescription, baseArgs.summaryOutputFile, baseArgs.repositoryPath);
|
|
360
|
-
//
|
|
361
|
-
|
|
362
|
-
expect(prompt).
|
|
363
|
-
|
|
364
|
-
//
|
|
302
|
+
// The standalone pre-flight tool is gone — its work folded into analyze_changes.
|
|
303
|
+
expect(prompt).not.toContain("skyramp_ui_analyze_changes");
|
|
304
|
+
expect(prompt).toContain("skyramp_analyze_changes");
|
|
305
|
+
// Captures stay in tool-result history — the old capturedBlueprints
|
|
306
|
+
// threading directive must be gone.
|
|
365
307
|
expect(prompt).not.toMatch(/capturedBlueprints/);
|
|
366
308
|
});
|
|
367
309
|
// Flutter support — both the generalised UI trigger wording and the
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { McpServer } from "@modelcontextprotocol/sdk/server/mcp.js";
|
|
2
|
+
export declare const ANALYSIS_URI_PREFIX = "skyramp://analysis";
|
|
3
|
+
/**
|
|
4
|
+
* Register MCP Resources for analysis data access.
|
|
5
|
+
*
|
|
6
|
+
* Resources provide read-only, token-efficient access to analysis data
|
|
7
|
+
* via sessionId. The state file is an internal backing store.
|
|
8
|
+
*
|
|
9
|
+
* URI scheme:
|
|
10
|
+
* skyramp://analysis/{sessionId}/summary
|
|
11
|
+
* skyramp://analysis/{sessionId}/endpoints
|
|
12
|
+
* skyramp://analysis/{sessionId}/endpoints/{+path}
|
|
13
|
+
* skyramp://analysis/{sessionId}/endpoints/{+path}/{method}
|
|
14
|
+
* skyramp://analysis/{sessionId}/scenarios
|
|
15
|
+
* skyramp://analysis/{sessionId}/diff
|
|
16
|
+
*/
|
|
17
|
+
export declare function registerAnalysisResources(server: McpServer): void;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
2
|
+
export declare class AnalyticsService {
|
|
3
|
+
static pushTestGenerationToolEvent(toolName: string, result: CallToolResult, params: Record<string, any>): Promise<void>;
|
|
4
|
+
static pushMCPToolEvent(toolName: string, result: CallToolResult | undefined, params: Record<string, string>): Promise<void>;
|
|
5
|
+
/**
|
|
6
|
+
* Track server crash events
|
|
7
|
+
*/
|
|
8
|
+
static pushServerCrashEvent(crashType: string, errorMessage: string, errorStack?: string): Promise<void>;
|
|
9
|
+
/**
|
|
10
|
+
* Track tool timeout events
|
|
11
|
+
*/
|
|
12
|
+
static pushToolTimeoutEvent(toolName: string, timeoutMs: number, params: Record<string, string>): Promise<void>;
|
|
13
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|