@skyramp/mcp 0.3.8 → 0.4.0-rc.1
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 +1 -1
- package/build/commands/commandLibrary.js +3 -3
- package/build/commands/recommendTestsAndExecuteCommand.d.ts +1 -1
- package/build/commands/recommendTestsAndExecuteCommand.js +35 -20
- package/build/commands/testThisEndpointCommand.js +35 -19
- package/build/index.js +9 -3
- package/build/playwright/blueprintDigest.d.ts +15 -0
- package/build/playwright/blueprintDigest.js +152 -0
- package/build/playwright/blueprintDigestStore.d.ts +31 -0
- package/build/playwright/blueprintDigestStore.js +117 -0
- package/build/playwright/registerPlaywrightTools.js +60 -12
- package/build/playwright/traceRecordingPrompt.js +8 -7
- package/build/prompts/enhance-assertions/sharedAssertionRules.js +9 -8
- package/build/prompts/enhance-assertions/uiAssertionsPrompt.js +24 -2
- package/build/prompts/promptAssets.d.ts +20 -0
- package/build/prompts/promptAssets.js +55 -0
- package/build/prompts/sut-setup/modes/dockerComposePrompt.js +19 -5
- package/build/prompts/test-maintenance/actionsInstructions.d.ts +4 -0
- package/build/prompts/test-maintenance/actionsInstructions.js +14 -2
- package/build/prompts/test-maintenance/drift-analysis-prompt.d.ts +0 -10
- package/build/prompts/test-maintenance/drift-analysis-prompt.js +2 -11
- package/build/prompts/test-maintenance/uiDriftAnalysisSections.js +8 -4
- package/build/prompts/test-recommendation/diffExecutionPlan.d.ts +5 -22
- package/build/prompts/test-recommendation/diffExecutionPlan.js +37 -465
- package/build/prompts/test-recommendation/recommendationSections.d.ts +7 -17
- package/build/prompts/test-recommendation/recommendationSections.js +67 -309
- package/build/prompts/test-recommendation/recommendationShared.d.ts +19 -47
- package/build/prompts/test-recommendation/recommendationShared.js +49 -155
- package/build/prompts/test-recommendation/registerRecommendTestsPrompt.d.ts +0 -5
- package/build/prompts/test-recommendation/registerRecommendTestsPrompt.js +10 -153
- package/build/prompts/test-recommendation/test-recommendation-prompt.d.ts +2 -29
- package/build/prompts/test-recommendation/test-recommendation-prompt.js +32 -457
- package/build/prompts/testbot/planDeclarations.d.ts +6 -0
- package/build/prompts/testbot/planDeclarations.js +9 -0
- package/build/prompts/testbot/testbot-prompts.d.ts +8 -0
- package/build/prompts/testbot/testbot-prompts.js +256 -381
- package/build/recommendation/answers.d.ts +35 -0
- package/build/recommendation/answers.js +96 -0
- package/build/recommendation/registerPlan.d.ts +49 -0
- package/build/recommendation/registerPlan.js +117 -0
- package/build/recommendation/runVerifiers.d.ts +10 -0
- package/build/recommendation/runVerifiers.js +49 -0
- package/build/recommendation/subjectStep.d.ts +42 -0
- package/build/recommendation/subjectStep.js +86 -0
- package/build/recommendation/types.d.ts +163 -0
- package/build/recommendation/types.js +20 -0
- package/build/recommendation/verifierContracts.d.ts +382 -0
- package/build/recommendation/verifierContracts.js +263 -0
- package/build/recommendation/verifiers/changedFile.d.ts +2 -0
- package/build/recommendation/verifiers/changedFile.js +82 -0
- package/build/recommendation/verifiers/citedPath.d.ts +12 -0
- package/build/recommendation/verifiers/citedPath.js +35 -0
- package/build/recommendation/verifiers/coverage.d.ts +7 -0
- package/build/recommendation/verifiers/coverage.js +617 -0
- package/build/recommendation/verifiers/deliveredMatchesPlan.d.ts +11 -0
- package/build/recommendation/verifiers/deliveredMatchesPlan.js +33 -0
- package/build/recommendation/verifiers/endpointGrounded.d.ts +17 -0
- package/build/recommendation/verifiers/endpointGrounded.js +128 -0
- package/build/recommendation/verifiers/existingCoverage.d.ts +6 -0
- package/build/recommendation/verifiers/existingCoverage.js +51 -0
- package/build/recommendation/verifiers/expectedOutcome.d.ts +31 -0
- package/build/recommendation/verifiers/expectedOutcome.js +105 -0
- package/build/recommendation/verifiers/removedElementGuarded.d.ts +2 -0
- package/build/recommendation/verifiers/removedElementGuarded.js +57 -0
- package/build/recommendation/verifiers/reportedCategory.d.ts +26 -0
- package/build/recommendation/verifiers/reportedCategory.js +84 -0
- package/build/recommendation/verifiers/screenRoute.d.ts +10 -0
- package/build/recommendation/verifiers/screenRoute.js +118 -0
- package/build/recommendation/verifiers/statedDifference.d.ts +6 -0
- package/build/recommendation/verifiers/statedDifference.js +140 -0
- package/build/recommendation/verifiers/uiElementGrounded.d.ts +7 -0
- package/build/recommendation/verifiers/uiElementGrounded.js +318 -0
- package/build/resources/analysisResources.js +1 -114
- package/build/resources/testbotResource.js +23 -13
- package/build/services/ModularizationService.js +2 -1
- package/build/services/TestDiscoveryService.d.ts +3 -72
- package/build/services/TestDiscoveryService.js +10 -303
- package/build/services/containerEnv.d.ts +1 -1
- package/build/services/containerEnv.js +12 -0
- package/build/skills/fixTestImportErrorsSkill.d.ts +13 -0
- package/build/skills/fixTestImportErrorsSkill.js +20 -0
- package/build/toolNames.d.ts +1 -0
- package/build/toolNames.js +1 -0
- package/build/tools/code-refactor/enhanceAssertionsTool.js +3 -3
- package/build/tools/code-refactor/modularizationTool.js +2 -1
- package/build/tools/executeSkyrampTestTool.d.ts +80 -0
- package/build/tools/executeSkyrampTestTool.js +246 -19
- package/build/tools/generate-tests/generateBatchScenarioRestTool.js +6 -0
- package/build/tools/generate-tests/generateContractRestTool.js +3 -3
- package/build/tools/generate-tests/planGuard.d.ts +2 -2
- package/build/tools/generate-tests/planGuard.js +78 -18
- package/build/tools/one-click/oneClickTool.d.ts +0 -1
- package/build/tools/one-click/oneClickTool.js +0 -5
- package/build/tools/submitReportTool.d.ts +48 -42
- package/build/tools/submitReportTool.js +576 -193
- package/build/tools/test-management/actionsTool.js +72 -4
- package/build/tools/test-management/analyzeChangesTool.d.ts +144 -48
- package/build/tools/test-management/analyzeChangesTool.js +212 -1219
- package/build/tools/test-management/analyzeTestHealthTool.js +13 -24
- package/build/tools/test-management/index.d.ts +1 -0
- package/build/tools/test-management/index.js +1 -0
- package/build/tools/test-management/registerTestPlanTool.d.ts +795 -172
- package/build/tools/test-management/registerTestPlanTool.js +609 -542
- package/build/tools/test-management/resolveScreenTool.d.ts +75 -0
- package/build/tools/test-management/resolveScreenTool.js +289 -0
- package/build/types/BlueprintDigest.d.ts +34 -0
- package/build/types/BlueprintDigest.js +1 -0
- package/build/types/RepositoryAnalysis.d.ts +20 -1559
- package/build/types/RepositoryAnalysis.js +2 -58
- package/build/types/StepMethod.d.ts +40 -0
- package/build/types/StepMethod.js +77 -0
- package/build/types/TestAnalysis.d.ts +12 -0
- package/build/types/TestExecution.d.ts +4 -0
- package/build/types/TestRecommendation.d.ts +24 -24
- package/build/types/TestRecommendation.js +91 -89
- package/build/types/TestbotPromptOptions.d.ts +0 -4
- package/build/types/TestbotReport.d.ts +64 -2
- package/build/utils/AnalysisStateManager.d.ts +79 -113
- package/build/utils/AnalysisStateManager.js +147 -57
- package/build/utils/assertion-verify/api-shared-lints.js +1 -1
- package/build/utils/assertion-verify/metrics.js +85 -36
- package/build/utils/assertion-verify/ui-lints.d.ts +0 -5
- package/build/utils/assertion-verify/ui-lints.js +32 -0
- package/build/utils/branchDiff.d.ts +63 -31
- package/build/utils/branchDiff.js +242 -94
- package/build/utils/containedPath.d.ts +18 -0
- package/build/utils/containedPath.js +73 -0
- package/build/utils/dartRouteExtractor.d.ts +18 -34
- package/build/utils/dartRouteExtractor.js +101 -173
- package/build/utils/featureFlags.d.ts +12 -0
- package/build/utils/featureFlags.js +14 -0
- package/build/utils/frontendSelectors.d.ts +48 -27
- package/build/utils/frontendSelectors.js +241 -80
- package/build/utils/pathMatching.d.ts +2 -4
- package/build/utils/pathMatching.js +2 -4
- package/build/utils/planMatchKeys.d.ts +38 -47
- package/build/utils/planMatchKeys.js +143 -81
- package/build/utils/rebaselineSnapshots.d.ts +24 -0
- package/build/utils/rebaselineSnapshots.js +65 -0
- package/build/utils/removedUiElements.d.ts +22 -0
- package/build/utils/removedUiElements.js +106 -0
- package/build/utils/reportVerification.d.ts +2 -6
- package/build/utils/reportVerification.js +61 -2
- package/build/utils/screenRoutes.d.ts +66 -0
- package/build/utils/screenRoutes.js +727 -0
- package/build/utils/sourceRouteExtractor.js +320 -112
- package/build/utils/testFileClassification.d.ts +11 -2
- package/build/utils/testFileClassification.js +44 -2
- package/build/utils/testFixtures.d.ts +5 -0
- package/build/utils/testFixtures.js +13 -0
- package/build/utils/utils.d.ts +0 -1
- package/build/utils/utils.js +0 -11
- package/build/utils/versions.d.ts +3 -3
- package/build/utils/versions.js +1 -1
- package/build/workspace/workspace.d.ts +12 -12
- package/node_modules/playwright/lib/mcp/skyramp/assertHiddenTool.js +56 -0
- package/node_modules/playwright/lib/mcp/skyramp/assertTool.js +2 -1
- package/node_modules/playwright/lib/mcp/skyramp/loadTraceTool.js +10 -0
- package/node_modules/playwright/lib/mcp/skyramp/skyRampImport.js +4 -1
- package/node_modules/playwright/lib/mcp/skyramp/traceRecordingBackend.js +160 -1
- package/node_modules/playwright/lib/mcp/test/skyRampExport.js +4 -2
- package/node_modules/playwright/node_modules/playwright-core/lib/server/codegen/skyramp/jsonlReader.js +1 -0
- package/node_modules/playwright/node_modules/playwright-core/lib/server/recorder/recorderSignalProcessor.js +2 -0
- package/node_modules/playwright/node_modules/playwright-core/lib/server/recorder.js +5 -1
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/{index.-Id052Lr.js → index.B7KbSQcC.js} +1 -1
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/index.html +1 -1
- package/node_modules/playwright/node_modules/playwright-core/package.json +1 -1
- package/node_modules/playwright/node_modules/playwright-core/src/server/codegen/skyramp/jsonlReader.ts +1 -1
- package/node_modules/playwright/node_modules/playwright-core/src/server/recorder/recorderSignalProcessor.ts +7 -0
- package/node_modules/playwright/node_modules/playwright-core/src/server/recorder.ts +6 -1
- package/node_modules/playwright/package.json +1 -1
- package/package.json +4 -3
- package/plugin/.claude-plugin/plugin.json +8 -0
- package/plugin/plugin.json +6 -0
- package/plugin/prompts/declaring-a-plan.md +20 -0
- package/plugin/prompts/generate-tests/context-fetching.md +4 -0
- package/plugin/prompts/generate-tests/execution-plan.md +63 -0
- package/plugin/prompts/generate-tests/generation.md +108 -0
- package/plugin/prompts/generate-tests/path-parameters.md +1 -0
- package/plugin/prompts/generate-tests/reasoning-protocol.md +17 -0
- package/plugin/prompts/generate-tests/tool-workflow-variants.md +61 -0
- package/plugin/prompts/generate-tests/tool-workflows.md +65 -0
- package/plugin/prompts/plan-tests.md +42 -0
- package/plugin/prompts/testbot-task1.md +82 -0
- package/plugin/skills/fix-test-import-errors/SKILL.md +98 -0
- package/build/prompts/test-recommendation/analysisOutputPrompt.d.ts +0 -84
- package/build/prompts/test-recommendation/analysisOutputPrompt.js +0 -369
- package/build/prompts/test-recommendation/fullRepoCatalog.d.ts +0 -7
- package/build/prompts/test-recommendation/fullRepoCatalog.js +0 -283
- package/build/prompts/test-recommendation/scopeAssessment.d.ts +0 -81
- package/build/prompts/test-recommendation/scopeAssessment.js +0 -359
- package/build/recommendation/budgeters/diversityBalancedBudgeter.d.ts +0 -7
- package/build/recommendation/budgeters/diversityBalancedBudgeter.js +0 -105
- package/build/recommendation/budgeters/fixedNBudgeter.d.ts +0 -7
- package/build/recommendation/budgeters/fixedNBudgeter.js +0 -11
- package/build/recommendation/budgeters/shared.d.ts +0 -32
- package/build/recommendation/budgeters/shared.js +0 -246
- package/build/recommendation/discriminators.d.ts +0 -37
- package/build/recommendation/discriminators.js +0 -379
- package/build/recommendation/diversity.d.ts +0 -47
- package/build/recommendation/diversity.js +0 -101
- package/build/recommendation/planRanker.d.ts +0 -65
- package/build/recommendation/planRanker.js +0 -83
- package/build/recommendation/testFixtures.d.ts +0 -25
- package/build/recommendation/testFixtures.js +0 -45
- package/build/types/FrontendIntegration.d.ts +0 -28
- package/build/types/FrontendIntegration.js +0 -22
- package/build/types/Recommendation.d.ts +0 -146
- package/build/types/Recommendation.js +0 -74
- package/build/utils/changedRoutes.d.ts +0 -29
- package/build/utils/changedRoutes.js +0 -87
- package/build/utils/frontendIntegration.d.ts +0 -9
- package/build/utils/frontendIntegration.js +0 -243
- package/build/utils/importerHop.d.ts +0 -135
- package/build/utils/importerHop.js +0 -489
- package/build/utils/pathAffinityClassification.d.ts +0 -49
- package/build/utils/pathAffinityClassification.js +0 -180
- package/build/utils/pythonMountPrefixes.d.ts +0 -25
- package/build/utils/pythonMountPrefixes.js +0 -347
- package/build/utils/repoScanner.d.ts +0 -34
- package/build/utils/repoScanner.js +0 -300
- package/build/utils/routeParsers.d.ts +0 -95
- package/build/utils/routeParsers.js +0 -951
- package/build/utils/scenarioDrafting.d.ts +0 -92
- package/build/utils/scenarioDrafting.js +0 -951
- package/build/utils/subjectEndpoints.d.ts +0 -19
- package/build/utils/subjectEndpoints.js +0 -98
- package/build/utils/uiPageEnumerator.d.ts +0 -172
- package/build/utils/uiPageEnumerator.js +0 -474
|
@@ -677,7 +677,8 @@ export class Recorder extends EventEmitter<RecorderEventMap> implements Instrume
|
|
|
677
677
|
const isSameDocument = !!event && !event.newDocument;
|
|
678
678
|
this._prevFrameUrls.set(frame, frame.url());
|
|
679
679
|
const url = userInitiatedNavigationUrl(event) ?? frame.url();
|
|
680
|
-
|
|
680
|
+
const fromBlankPage = isBlankUrl(prevUrl) && !isBlankUrl(url);
|
|
681
|
+
this._signalProcessor.signal(pageAlias!, frame, { name: 'navigation', url, isReload, isSameDocument, fromBlankPage });
|
|
681
682
|
}
|
|
682
683
|
|
|
683
684
|
private _onPopup(page: Page, popup: Page) {
|
|
@@ -716,6 +717,10 @@ function userInitiatedNavigationUrl(event?: NavigationEvent): string | undefined
|
|
|
716
717
|
return request.url();
|
|
717
718
|
}
|
|
718
719
|
|
|
720
|
+
function isBlankUrl(url: string | undefined): boolean {
|
|
721
|
+
return !url || url === 'about:blank';
|
|
722
|
+
}
|
|
723
|
+
|
|
719
724
|
function languageForFile(file: string): Language {
|
|
720
725
|
if (file.endsWith('.py'))
|
|
721
726
|
return 'python';
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@skyramp/mcp",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0-rc.1",
|
|
4
4
|
"main": "build/index.js",
|
|
5
5
|
"exports": {
|
|
6
6
|
".": "./build/index.js",
|
|
@@ -41,6 +41,7 @@
|
|
|
41
41
|
"files": [
|
|
42
42
|
"build/**/*.js",
|
|
43
43
|
"build/**/*.d.ts",
|
|
44
|
+
"plugin/**",
|
|
44
45
|
"README.md"
|
|
45
46
|
],
|
|
46
47
|
"bundleDependencies": [
|
|
@@ -70,12 +71,12 @@
|
|
|
70
71
|
"dependencies": {
|
|
71
72
|
"@modelcontextprotocol/sdk": "^1.24.3",
|
|
72
73
|
"@playwright/test": "^1.55.0",
|
|
73
|
-
"@skyramp/skyramp": "1.3.
|
|
74
|
+
"@skyramp/skyramp": "1.3.44",
|
|
74
75
|
"dockerode": "^5.0.0",
|
|
75
76
|
"fast-glob": "^3.3.3",
|
|
76
77
|
"js-yaml": "^4.1.1",
|
|
77
78
|
"picomatch": "^4.0.5",
|
|
78
|
-
"playwright": "file:vendor/skyramp-playwright-1.58.2-skyramp.8.14.
|
|
79
|
+
"playwright": "file:vendor/skyramp-playwright-1.58.2-skyramp.8.14.9.tgz",
|
|
79
80
|
"simple-git": "^3.30.0",
|
|
80
81
|
"ts-is-record": "^3.0.5",
|
|
81
82
|
"typescript": "^5.8.3",
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
## How to declare your plan
|
|
2
|
+
|
|
3
|
+
The procedure says how to plan. The description of each field in the tool schema says what to put in the field and what its check reads. Each objection says what to do next, and it contains the decision that the check cannot make for you.
|
|
4
|
+
|
|
5
|
+
## Answering an objection
|
|
6
|
+
|
|
7
|
+
Each objection contains an `objectionId`, the evidence for the objection, and a suggested next step. You have two options:
|
|
8
|
+
|
|
9
|
+
1. Change the plan and register it again.
|
|
10
|
+
2. Register the plan again with an entry in `answers`. The entry gives the `objectionId` and your answer.
|
|
11
|
+
|
|
12
|
+
Use only the ids that the last registration returned.
|
|
13
|
+
|
|
14
|
+
One objection has no answer: an objection with an id that starts with `coverage:stateTest:` closes only when the plan holds the test, so add the test.
|
|
15
|
+
|
|
16
|
+
The report shows each objection. If you gave an answer, the report shows the answer next to the objection. If you disagree with an objection, answer it. Do not leave it without an answer.
|
|
17
|
+
|
|
18
|
+
## If you find a test that is not in your plan
|
|
19
|
+
|
|
20
|
+
If you find a test that the diff needs and that is not in your plan, register the plan again with the new planned test. Then write the test. The report joins each delivered test to a plan planned test by id. The report refuses a contract test or an integration test that has no plan entry. This usually happens when you find a bug while you write or run the planned tests.
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
<context_fetching_protocol>
|
|
2
|
+
## Execution Plan Context
|
|
3
|
+
Before calling any tool, replace every `<from source>` placeholder in the tool call parameters with actual values read from the relevant source file (handler, schema, or model). Do not proceed with placeholders still present — every parameter must trace to a concrete source.
|
|
4
|
+
</context_fetching_protocol>
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
# Generation step bodies
|
|
2
|
+
|
|
3
|
+
Each section is one step of the recommendation prompt's generation plan. A `{name}`
|
|
4
|
+
in the text is a value the prompt fills in. The analysis and planning instruction
|
|
5
|
+
that used to live here is now in `../SKILL.md` and `declaring-a-plan.md`.
|
|
6
|
+
|
|
7
|
+
## Parameter grounding
|
|
8
|
+
|
|
9
|
+
Quote the source you read while planning in `<source_evidence>` blocks — include route handler signatures, request body schema fields, response shapes, and computed field formulas. Use these quotes to derive tool call parameters. Resolve:
|
|
10
|
+
- **Auth middleware** — check for known signals ({authMiddlewarePatterns}). If any match, override `authHeader` and `authScheme` even if workspace.yml says authType: none. **If no known signal matches but {enrichSurface} shows security-adjacent code** (decorators like `@requiresRole`/`@Protected`, function names like `validateToken`/`checkPermission`/`verifyHMAC`, or imports from auth/security packages), read the relevant source file to determine the actual auth scheme before proceeding. Auth handling for `skyramp_integration_test_generation` with `scenarioFile` is covered in the Tool Workflows section below.
|
|
11
|
+
- Business rules and formulas (e.g. total_cost = compute * rate + memory * rate)
|
|
12
|
+
- State transitions and domain constraints (e.g. budget cannot drop below current spend)
|
|
13
|
+
- Validation logic (field constraints, cross-field dependencies)
|
|
14
|
+
- Security boundaries your plan does not already cover
|
|
15
|
+
|
|
16
|
+
A candidate is worth planning when it is specific to THIS codebase — derived from a concrete business rule, formula, constraint, state transition or boundary in the changed files, not a general pattern that fits any API. Attack-surface `security_boundary` tests keep their value: they cover sibling destructive endpoints that could bypass the auth boundary this diff changed.
|
|
17
|
+
|
|
18
|
+
{testPatternGuidelines}
|
|
19
|
+
|
|
20
|
+
**Source-code validation gates:**
|
|
21
|
+
- **Cascade vs referential integrity**: If both a cascade-delete and a delete-blocked scenario appear for the same resource pair, the source foreign-key delete policy says which one the code can actually do (ON DELETE CASCADE / cascade=True / onDelete: 'CASCADE' → cascade-delete; RESTRICT/PROTECT/no annotation → delete-blocked). The other variant asserts a policy this codebase does not have.
|
|
22
|
+
- **Unique constraints**: Before you plan a unique-constraint scenario (duplicate POST → 409), confirm the code enforces it: SQL UNIQUE index, Mongoose unique: true, Prisma @unique, or explicit duplicate-check code. If the backend is Redis, schema-less, or has no explicit constraint in the changed files, nothing enforces uniqueness, so there is no 409 to catch.
|
|
23
|
+
|
|
24
|
+
## Execute the plan
|
|
25
|
+
|
|
26
|
+
Write the tests the plan you registered holds, with its objections answered or its cause removed.
|
|
27
|
+
|
|
28
|
+
Every scenario must follow the foreign-key relationships the codebase really has. Never pair unrelated resources.
|
|
29
|
+
Use the field names and values from the `<source_evidence>` blocks you quoted in Step {enrichStep} to fill all tool call parameters. Prefer reusing Step {enrichStep} evidence when it already resolves a placeholder, but if a placeholder cannot be replaced with concrete values from files already read, you may read the specific schema, model, or handler file needed to resolve it. Assert response field values, not just status codes.
|
|
30
|
+
|
|
31
|
+
{testQualityCriteria}
|
|
32
|
+
|
|
33
|
+
{generationRules}
|
|
34
|
+
|
|
35
|
+
**A missing input is not a reason to skip a test:** No OpenAPI spec → use source code for shapes. No traces → provide `skyramp_start_trace_collection` instructions. No backend trace → use the scenario pipeline.
|
|
36
|
+
|
|
37
|
+
If the work shows you a test worth writing that the plan does not hold — a flaw you find while writing, most often — register the plan again with it first.
|
|
38
|
+
|
|
39
|
+
## UI and E2E tool workflow
|
|
40
|
+
|
|
41
|
+
**UI/E2E tool workflow** — use it for each UI or E2E test your plan holds:
|
|
42
|
+
- **E2E**: {e2eStep}
|
|
43
|
+
- **UI**: {uiStep}
|
|
44
|
+
Derive scenario names and steps from the actual changed frontend files. If your plan holds no UI or E2E test, skip this.
|
|
45
|
+
|
|
46
|
+
**Empty page**: If a page carries no test data — an empty state, nothing to interact with — write the Playwright test from the component structure, event handlers and expected behavior you read in the diff, or seed the data through `page.evaluate()` or an API call. At minimum assert that the page renders and that its interactive elements carry the right attributes. An empty page is not a reason to write no test.
|
|
47
|
+
|
|
48
|
+
## E2E with a trace
|
|
49
|
+
|
|
50
|
+
Use discovered trace/recording files with `skyramp_e2e_test_generation`.
|
|
51
|
+
|
|
52
|
+
## E2E with no trace
|
|
53
|
+
|
|
54
|
+
Follow the E2E rule in the Tool Workflows section: skip the generation call and say in the report that both traces have to be recorded in a live environment first.
|
|
55
|
+
|
|
56
|
+
## UI with a trace
|
|
57
|
+
|
|
58
|
+
Use the trace you exported while walking that behaviour, or an existing Playwright `.zip` trace, with `skyramp_ui_test_generation`.
|
|
59
|
+
|
|
60
|
+
## UI with no trace
|
|
61
|
+
|
|
62
|
+
Record again with the UI steps in the Tool Workflows section — only when the plan changed that test after you registered it, or when no trace covers it — then call `skyramp_ui_test_generation` with `outputDir` set to {frontendTestDir}.
|
|
63
|
+
|
|
@@ -0,0 +1,108 @@
|
|
|
1
|
+
# Generation rules and the sections around them
|
|
2
|
+
|
|
3
|
+
Each section is one block of the recommendation prompt. A `{name}` is a value
|
|
4
|
+
the prompt fills in per run.
|
|
5
|
+
|
|
6
|
+
## Architect preamble
|
|
7
|
+
|
|
8
|
+
You are acting as a Skyramp Integration Architect. You will receive {scopeInput}. Your responsibility is to map test intent to the Skyramp generation spec with precision. No guessing — derive all parameters from the codebase, workspace config, and provided context only.
|
|
9
|
+
|
|
10
|
+
Your task:
|
|
11
|
+
1. **{scopeTask}** — prioritize tests most likely to catch real production bugs (state machine violations, cross-resource data integrity, computed field errors, security boundary bypasses) over trivial coverage
|
|
12
|
+
2. **Register your plan, then write the tests it holds** by calling Skyramp MCP generation tools — only these types: **integration, contract, E2E, UI**. Never smoke. Never fuzz.
|
|
13
|
+
3. **Account for existing coverage** — when an existing test already covers an endpoint + test type, make your planned test a maintenance update of that test, or say how the two differ
|
|
14
|
+
|
|
15
|
+
Every tool parameter must trace to a concrete source: repository analysis, source code, or OpenAPI spec. Do not invent field names, request shapes, base URLs, or auth values. If a required value is unknown, read the relevant source file before calling the tool.
|
|
16
|
+
|
|
17
|
+
## Test pattern guidelines
|
|
18
|
+
|
|
19
|
+
### Test Pattern Guidelines
|
|
20
|
+
|
|
21
|
+
- CRUD lifecycle per resource group (Create → Read → Update → Delete)
|
|
22
|
+
- Auth flow (Register → Login → Access protected → Token refresh → Logout)
|
|
23
|
+
- Pagination & filtering (boundary values, empty results, large page sizes)
|
|
24
|
+
- Error responses (400, 401, 403, 404, 409, 422 — each with a specific trigger)
|
|
25
|
+
**422 prerequisite:** Only recommend a 422 / missing-field test when you can confirm from source or schema that the field is **required**. In source, optional types such as `Optional[str]` or `field?: T` are not omission failures. In OpenAPI, omission is controlled solely by the parent schema's `required` list; `nullable: true` only permits an explicitly provided `null` value. Also verify the exact error body field name returned by the handler (e.g. `detail` in FastAPI, `message` in Express) before asserting a specific string like `"missing"` — the server may return a different key or value.
|
|
26
|
+
- **Middleware chains**: If auth/rate-limit/logging middleware exists, test the chain (e.g., rate limit hit → auth still checked → correct error returned)
|
|
27
|
+
- **N+1 query risk**: If list endpoints join related data (e.g., orders with products), test with large datasets
|
|
28
|
+
- **State machines**: If resources have status transitions (draft→published→archived), test invalid transitions (e.g., archived→draft should fail)
|
|
29
|
+
- **Cascade deletes**: Only recommend after reading source code to confirm which resource holds the foreign key. The resource with the foreign key is the child; the one it points to is the parent. Example: if orders.product_id references products, then products is the parent — deleting a product tests whether orders are protected or cascade-deleted. Getting this backwards (treating the child as the parent) produces a nonsensical test.
|
|
30
|
+
- **Race conditions**: If concurrent writes are possible (inventory deduction, counter increment), test concurrent requests
|
|
31
|
+
- **Computed fields**: If response contains derived values (total, average, count), verify computation with known inputs (e.g., total_cost = compute_seconds * rate + memory_mb * rate + external_cost)
|
|
32
|
+
- **Mutation with collection modification**: See the mutation-recalc rule in the Tool Workflows section — it is the most common source of user-reported bugs, so prefer it over a single-field update on the same endpoint.
|
|
33
|
+
- **Webhook/event side effects**: If endpoints trigger async operations, test that side effects occur (e.g., POST /orders triggers notification)
|
|
34
|
+
- **Cross-user isolation**: If resources are owned by users, test that user B cannot access/modify user A's resources (GET /users/{other_id}/data → 403 Forbidden)
|
|
35
|
+
- **Range/boundary invariants**: If business rules cap values (max retries, min balance, discount ≤ subtotal), test the boundary (e.g., set retries to max+1 → expect rejection)
|
|
36
|
+
- **Breaking change migration**: If the diff renames a route, changes auth headers, or removes a required field, test both old path (should 404) and new path (should succeed)
|
|
37
|
+
|
|
38
|
+
## Test quality criteria
|
|
39
|
+
|
|
40
|
+
### What Makes a Good Test
|
|
41
|
+
|
|
42
|
+
**Integration tests** should demonstrate cross-resource data flow — step A creates data
|
|
43
|
+
that step B depends on (e.g., create product → create order referencing that product's ID →
|
|
44
|
+
verify order contains correct product). Single-resource CRUD alone is not an integration test.
|
|
45
|
+
Use actual field names and values from the source code schema or OpenAPI schema (not `{}` or invented field names); verify response data, not just status codes.
|
|
46
|
+
|
|
47
|
+
**Contract tests** (single-step) are the right choice for: error-handling scenarios on a single
|
|
48
|
+
endpoint (e.g., PATCH/GET/DELETE a nonexistent resource → 404, POST with invalid payload → 422),
|
|
49
|
+
validation boundary checks, and any test that exercises one endpoint's API contract in isolation.
|
|
50
|
+
Do NOT add setup steps just to avoid hardcoding an ID — use a realistic hardcoded nonexistent ID
|
|
51
|
+
(e.g., 99999 or a random UUID) and keep it a single-step contract test.
|
|
52
|
+
|
|
53
|
+
**E2E tests** should follow realistic user journeys end-to-end: browse products → search →
|
|
54
|
+
add to cart → checkout. Verify that frontend actions trigger the correct API calls and
|
|
55
|
+
that the UI reflects backend state.
|
|
56
|
+
|
|
57
|
+
**UI tests** should exercise component behavior and interaction flows: fill form → validate
|
|
58
|
+
inputs → submit → see confirmation. Include visual state changes (loading, error, empty)
|
|
59
|
+
and accessibility checks.
|
|
60
|
+
|
|
61
|
+
## Generation rules
|
|
62
|
+
|
|
63
|
+
### Generation Guidelines
|
|
64
|
+
|
|
65
|
+
**Available test types:** integration, contract, E2E, UI. **No smoke or fuzz tests.**
|
|
66
|
+
Choose based on what adds the most value for this PR's changes. The contract test modes
|
|
67
|
+
this build supports are in the Tool Workflows section.
|
|
68
|
+
|
|
69
|
+
**Scenario fidelity:** Every workflow scenario should reflect the actual resource
|
|
70
|
+
relationships in the code.
|
|
71
|
+
|
|
72
|
+
For a UI test, use the trace you exported while walking that behaviour in the planning
|
|
73
|
+
procedure. Record again with the Playwright browser tools (`browser_navigate`,
|
|
74
|
+
`browser_click`, etc.) and export via `skyramp_export_zip` only when the plan changed that
|
|
75
|
+
test after you registered it, or when no trace covers it.
|
|
76
|
+
|
|
77
|
+
### The SDK helpers a generated TypeScript test uses
|
|
78
|
+
|
|
79
|
+
All of these come from `@skyramp/skyramp`, the import the generated file already has.
|
|
80
|
+
|
|
81
|
+
- `client.sendRequest({ url, path, method, body, headers, dataOverride, queryParams })` sends one request. `body` is a JSON string. `headers` is a plain object.
|
|
82
|
+
- The client adds no authorization header on its own. Put the bearer token in `headers` as an `Authorization` header whose value is the word Bearer, a space, and `getEnv("SKYRAMP_TEST_TOKEN")`.
|
|
83
|
+
- `headers` is per request. A step that sends no `headers` is the unauthenticated call. A step that needs another user's identity sends that user's token in its own `headers`.
|
|
84
|
+
- A second identity is a second token. Create the user through the API, log that user in the same way the first token was obtained, and use the returned token on the steps that act as that user.
|
|
85
|
+
- `response.statusCode` is the status. `getResponseValue(response, "<path>")` returns the value at that path in the response body, or `null` when the path is absent. Index an array element with `.0`, `.1`.
|
|
86
|
+
- `dataOverride: { field: value }` replaces a top-level field of `body` by name. For a nested field, write the value into the body string with `${...}`.
|
|
87
|
+
- `uniqueSuffix("base")` returns `base` with a run-unique suffix. Use it through `dataOverride` on a field the server requires to be unique; an email keeps its domain.
|
|
88
|
+
- `getBaseUrl("SKYRAMP_TEST_BASE_URL", "<fallback>")` and `getEnv("<NAME>")` read the environment.
|
|
89
|
+
|
|
90
|
+
## Before you finish a test
|
|
91
|
+
|
|
92
|
+
Each of these is about the test file you are writing. Correct it in the file.
|
|
93
|
+
|
|
94
|
+
- A negative assertion on a body (`not.toContain`, `not.toBe`) stands beside a positive one on the same response — the status, or a field the response must carry. A negative assertion alone passes on the wrong response too.
|
|
95
|
+
- An assertion on a change checks the value the change states. If the change says the first response is a MISS, assert MISS, not one of MISS or HIT. If the value depends on test order or timing, do not assert either value: answer the change's objection with that reason.
|
|
96
|
+
- An issue you will report at `high` or `critical` has a test, or one sentence saying why no test can reach it.
|
|
97
|
+
- A test deletes each record it created, in its last steps. If the API has no delete for that record, say so in the test's description.
|
|
98
|
+
- A test never leaves a record it did not create in a different state from the one it found. A seeded record may be the starting state of a mutation test when the test restores it afterwards (a reset endpoint, or the reverse mutation) or when the mutation under test is the one that should be REFUSED, which leaves the record unchanged.
|
|
99
|
+
- A field the diff adds to a record appears in every expected body of that record, in new and in updated tests.
|
|
100
|
+
- A timestamp is parsed and compared as a time, never indexed as characters.
|
|
101
|
+
- A test declared to fail asserts the fixed behaviour, not today's status code. A `why` saying the test turns green after a fix has to be true of every assertion in the file, not just the last one.
|
|
102
|
+
|
|
103
|
+
## Verification checklist
|
|
104
|
+
|
|
105
|
+
<verification>
|
|
106
|
+
Before finalizing your output, verify:
|
|
107
|
+
1. **scenarioFile**: `skyramp_integration_test_generation` uses the exact `filePath` returned by `skyramp_batch_scenario_test_generation` — not a guessed or hardcoded filename.
|
|
108
|
+
</verification>
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
**Path parameters:** keep the placeholder in `endpointURL` (e.g. `/coupons/{coupon_id}`). Pass the value via `pathParams` (e.g. `coupon_id=<random-uuid-v4>`). Use example values from the OpenAPI schema if available; otherwise generate a fresh random UUID v4 — not all-zeros or repeated-digit patterns.
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
<reasoning_protocol>
|
|
2
|
+
## Parameter Grounding Rule
|
|
3
|
+
Before each GENERATE tool call, confirm WHERE each key value comes from:
|
|
4
|
+
|
|
5
|
+
- **requestBody / responseBody fields** → source code schema (Zod, Pydantic, DTO), enriched scenario, or OpenAPI spec. **The generation tool rejects empty `{}` request bodies for POST/PUT/PATCH** — read the source schema first if the fields are unknown.
|
|
6
|
+
- **endpointURL** → workspace `baseUrl` + endpoint path (both required — never path alone)
|
|
7
|
+
- **authHeader / authScheme** → workspace config or OpenAPI `securitySchemes`
|
|
8
|
+
- **Foreign-key path params** → chained from a prior step's response — never invented or hardcoded. Common field names: `id`, `uuid`, `_id`, `*_id`; use whatever identifier field the server returns for this resource. The chaining source can be a response body (POST or GET), a response header (e.g. `Location`), or a cookie.
|
|
9
|
+
- **Names / string values** → realistic. Do NOT hardcode a timestamp/uuid suffix. Instead, for create fields that carry a UNIQUE constraint (e.g. `name`, `slug`, `email` — confirm from the source schema: `unique=True`, SQL `UNIQUE`, DTO), list their field paths in the step's `uniqueFields` (gjson notation) — the generator injects a run-unique value so re-runs don't 409.
|
|
10
|
+
|
|
11
|
+
## Bug-Target Rule
|
|
12
|
+
For each test you plan, include one sentence in your output (before the tool calls) stating the specific bug or failure it targets, derived from your source-code reading. Example: "Targets: order total miscalculation — total_amount = sum(item.price × item.quantity) should recompute when items array changes."
|
|
13
|
+
|
|
14
|
+
Read the source and name the target before you plan the test.
|
|
15
|
+
|
|
16
|
+
If a value cannot be sourced, read the relevant source file before calling the tool. Do not proceed with invented values.
|
|
17
|
+
</reasoning_protocol>
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
# Tool workflow variants
|
|
2
|
+
|
|
3
|
+
Each pair below is one sentence the run chooses between: the workspace auth
|
|
4
|
+
shape, and whether consumer-mode contract tests are built in.
|
|
5
|
+
|
|
6
|
+
## Auth verification required
|
|
7
|
+
|
|
8
|
+
**Auth Verification Required:** The workspace config indicates no authentication, but you MUST verify this independently before omitting auth:
|
|
9
|
+
1. **OpenAPI spec** → check `securitySchemes` / `securityDefinitions` for `type: http`, `type: apiKey`, or `type: oauth2`
|
|
10
|
+
2. **Source code** → look for the auth middleware signals listed in Step {enrichStep} of the Generation Plan.
|
|
11
|
+
3. **Route definitions** → check if routes have auth decorators or middleware applied
|
|
12
|
+
4. **Still unknown** → proceed with `authHeader: ""` and note "auth pattern unrecognized" in your recommendation description.
|
|
13
|
+
If you find auth requirements, pass the appropriate `authHeader` and `authScheme` to EVERY tool call. Only pass `authHeader: ""` if you confirm the API is truly unauthenticated.
|
|
14
|
+
**NEVER invent auth header names.** Only use header names explicitly defined in route/middleware source code or derived from OpenAPI security schemes. For `apiKey` schemes with `in: header`, use the scheme's `name` value. For `http` bearer/basic schemes, use `Authorization`. Do not treat `securitySchemes` map keys as header names, and do not guess headers from naming conventions such as `X-Admin-Key`, `X-API-Token`, or `X-Auth-Header` unless that exact header is explicitly defined in source or schema.
|
|
15
|
+
|
|
16
|
+
## Auth scheme
|
|
17
|
+
|
|
18
|
+
**Auth Scheme:** {authTypeLine}
|
|
19
|
+
**Where to find the scheme** (check in order):
|
|
20
|
+
1. **OpenAPI spec** → look at `securitySchemes` / `securityDefinitions` for `type: http, scheme: bearer` or `type: apiKey`
|
|
21
|
+
2. **Source code** → the auth middleware signals listed in Step {enrichStep} of the Generation Plan
|
|
22
|
+
3. **Fallback** → when the workspace sets `api.authType`, use that value as the scheme if the source is inconclusive; when it does not, use `"Bearer"` only if the project clearly uses JWT or OAuth, and `authScheme: ""` otherwise
|
|
23
|
+
Pass the prefix as `authScheme` (e.g., `"Bearer"`, `"Token"`, `"Basic"`). If the API uses raw tokens with no prefix, pass `authScheme: ""`.
|
|
24
|
+
**Do NOT guess the scheme.**
|
|
25
|
+
To skip auth on an unauthenticated endpoint, pass `authHeader: ""`.
|
|
26
|
+
|
|
27
|
+
## Auth header, not Authorization
|
|
28
|
+
|
|
29
|
+
**Auth Header:** `{authHeader}` is a non-Authorization header — a placeholder token is auto-generated. Just pass `authHeader` — do NOT pass `authScheme` (it is only for Authorization headers and will be ignored).
|
|
30
|
+
To skip auth for unauthenticated endpoints, pass `authHeader: ""`.
|
|
31
|
+
|
|
32
|
+
## Integration auth, workspace handles it
|
|
33
|
+
|
|
34
|
+
omit ALL auth params (passing auth alongside workspace authType causes "{authConflictError}").
|
|
35
|
+
|
|
36
|
+
## Integration auth, header only
|
|
37
|
+
|
|
38
|
+
pass `{authHeaderOnlyParams}` only (no `authScheme`, no `authToken`).
|
|
39
|
+
|
|
40
|
+
## Auth line, none configured
|
|
41
|
+
|
|
42
|
+
**No Auth (from workspace config):** Workspace indicates no authentication. **Verify independently** — if you find auth in the OpenAPI spec or source code, override with the correct `authHeader` and `authScheme`.
|
|
43
|
+
|
|
44
|
+
## Auth line, configured
|
|
45
|
+
|
|
46
|
+
**Auth params:** `{authCallParams}` — pass to EVERY tool call below.
|
|
47
|
+
|
|
48
|
+
## Contract modes, consumer enabled
|
|
49
|
+
|
|
50
|
+
**Contract test mode selection — set based on this service's role at the boundary:**
|
|
51
|
+
- `providerMode: true` — this service IS the API; validates the implementation matches the spec.
|
|
52
|
+
Use for new or modified endpoints this codebase owns.
|
|
53
|
+
- `consumerMode: true` — this service CALLS another API; validates outbound requests conform to the downstream contract.
|
|
54
|
+
Use when the endpoint's implementation makes HTTP calls to external services (look for fetch/axios/httpx/http.Client/service clients).
|
|
55
|
+
A request-aware mock stands in for the real downstream service — no live dependency needed.
|
|
56
|
+
- **Both modes** (`providerMode: true, consumerMode: true`) — same output as omitting both flags. Generates both consumer and provider contract tests. Use when the diff contains BOTH provider signals (new/modified endpoint handlers) AND consumer signals (outbound HTTP client calls to another service).
|
|
57
|
+
|
|
58
|
+
## Contract modes, provider only
|
|
59
|
+
|
|
60
|
+
**Contract tests — provider-only:**
|
|
61
|
+
Only provider-side contract tests are supported. Pass `providerMode: true` for new or modified endpoints this codebase owns.
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
## How to Generate Tests — Tool Workflows
|
|
2
|
+
|
|
3
|
+
**Contract**: The following tool signatures are strict technical contracts. Every parameter should match the schema exactly. Omit optional parameters rather than guessing values. If a required field cannot be resolved, fetch context first.
|
|
4
|
+
|
|
5
|
+
**Before every tool call**: Confirm WHERE each key value comes from — source code schema, enriched scenario, or OpenAPI spec. See Mandatory Reasoning Protocol above.
|
|
6
|
+
|
|
7
|
+
{authHeaderLine}
|
|
8
|
+
{authGuidance}
|
|
9
|
+
|
|
10
|
+
**For multi-endpoint workflows (integration tests) — Batch Scenario → Integration pipeline:**
|
|
11
|
+
1. Call `skyramp_batch_scenario_test_generation` with ALL steps in a single call: `scenarioName`, `destination`,
|
|
12
|
+
`baseURL`, `{authCallParams}`, and a `steps` array where each element has `method`, `path`, `requestBody` OR `queryParams`, `responseBody`, `statusCode`.
|
|
13
|
+
`statusCode` is optional for DELETE/GET/PUT/PATCH — defaults: DELETE→204 and GET/PUT/PATCH→200. For POST, always pass the confirmed `statusCode` explicitly after reading the handler, OpenAPI spec, existing test, or trace: resource-creation endpoints commonly return `201`, while action-style endpoints often return `200`.
|
|
14
|
+
**Action-style POST check:** Treat action verbs as path segments, not substrings. If the terminal path segment, or another clearly action-oriented segment, is a verb signalling an operation rather than resource creation (e.g. `/run`, `/trigger`, `/execute`, `/deploy`, `/submit`, `/start`, `/stop`, `/cancel`, `/send`, `/publish`, `/process`, `/validate`, `/check`, `/apply`, `/retry`), confirm the actual status code before setting `statusCode` — do NOT infer `201` from POST alone.
|
|
15
|
+
**OpenAPI spec is NOT required.** `apiSchema` is OPTIONAL — omit it if no spec exists.
|
|
16
|
+
**CRITICAL — Query params vs request body:**
|
|
17
|
+
- For **POST/PUT/PATCH**: use `requestBody` with realistic field values from source code schemas.
|
|
18
|
+
- For **GET/DELETE with search/filter/pagination**: use `queryParams`. Do not put query parameters in `requestBody` for GET requests — GET request bodies are non-standard and may be ignored or rejected.
|
|
19
|
+
- For **GET by ID**: no `requestBody` or `queryParams` needed — the ID is in the path.
|
|
20
|
+
`responseBody` should match the actual API response shape from source code (including all fields
|
|
21
|
+
returned by the controller — e.g., `id`, `ownerId`, `createdAt`, included relations like `collection`, `tags`).
|
|
22
|
+
Wrap in `{"response": ...}` if the API uses an envelope pattern. If omitted, a synthetic response is generated.
|
|
23
|
+
Inspect the source code to determine the correct request AND response body shapes — avoid sending `{}`.
|
|
24
|
+
**For PATCH/PUT mutation-recalc scenarios:** The request body should include the child
|
|
25
|
+
collection array (e.g. `"items": [{"product_id": <chained from prior POST>, "quantity": 2}]`).
|
|
26
|
+
Never send a PATCH that only modifies metadata (discount, status) without also including the
|
|
27
|
+
items/products collection — such a test will not catch collection-level or total-recalculation
|
|
28
|
+
bugs, and it is where user-reported bugs concentrate, so prefer it over a single-field update
|
|
29
|
+
on the same endpoint. Read the source for the child-collection field name, its foreign-key and
|
|
30
|
+
quantity sub-fields, and the total formula. Then assert the child items in the response
|
|
31
|
+
(product_id, quantity, unit_price) and the recomputed total, not just the top-level metadata.
|
|
32
|
+
For UNIQUE-constrained create fields, set the step's `uniqueFields` (gjson paths) rather than
|
|
33
|
+
hardcoding timestamp suffixes — the generator makes them run-unique so re-runs don't 409.
|
|
34
|
+
For every resource-creating step (POST/PUT), also add a matching DELETE step for the created
|
|
35
|
+
resource (path ID chained from the create response) so the scenario cleans up after itself.
|
|
36
|
+
For GET/PUT/DELETE with path IDs, use a placeholder — chaining resolves the real ID.
|
|
37
|
+
2. Produces a `scenario_<name>.json` in the same `outputDir` as the test files (not `.skyramp/`).
|
|
38
|
+
3. Call `skyramp_integration_test_generation` with `scenarioFile`: {integrationAuthNote}
|
|
39
|
+
Do NOT pass `chainingKey` — defaults to `response.id`. After generation, the testbot
|
|
40
|
+
will verify and fix path param chaining in the generated test.
|
|
41
|
+
|
|
42
|
+
**For single-endpoint tests (contract):**
|
|
43
|
+
`skyramp_contract_test_generation` with `endpointURL` (full URL incl. base + path), `method`,
|
|
44
|
+
`{authCallParams}`, and `requestData` from source code schemas.
|
|
45
|
+
If an OpenAPI spec exists, ALSO pass `apiSchema` — it enables schema-aware validation
|
|
46
|
+
(contract tests verify response structure against the spec).
|
|
47
|
+
Without a spec, `endpointURL` alone is sufficient.
|
|
48
|
+
{pathParamUuidGuidance}
|
|
49
|
+
|
|
50
|
+
{contractModeSelection}
|
|
51
|
+
|
|
52
|
+
**For UI tests:**
|
|
53
|
+
1. `browser_navigate` to the target URL (from workspace `api.baseUrl`)
|
|
54
|
+
2. `browser_snapshot` to see the page (ARIA tree)
|
|
55
|
+
3. Interact using `browser_click`, `browser_type`, `browser_fill_form`, etc.
|
|
56
|
+
4. `browser_snapshot` after each interaction that changes the page
|
|
57
|
+
5. `skyramp_export_zip` with an **absolute** output path: `<repositoryPath>/.skyramp/<test_name>_trace.zip`
|
|
58
|
+
6. `skyramp_ui_test_generation` with `playwrightInput` = the **absolute** path of the exported zip, and `outputDir` = {frontendTestDir} (e.g. `frontend/tests`). Do NOT use the backend service's testDirectory — UI tests must go in the frontend service's test directory.
|
|
59
|
+
|
|
60
|
+
Tips: For custom dropdowns (Radix, MUI): click combobox → snapshot → click option (NOT `browser_select_option`).
|
|
61
|
+
|
|
62
|
+
**For E2E tests (mixed PR — both backend and frontend changed):**
|
|
63
|
+
Only generate when pre-existing backend trace `.json` AND Playwright `.zip` both exist in the repo.
|
|
64
|
+
Use them directly with `skyramp_e2e_test_generation`.
|
|
65
|
+
If traces are missing, skip E2E and say in the report that both traces have to be recorded first.
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
|
|
2
|
+
# Plan the tests a pull request needs
|
|
3
|
+
|
|
4
|
+
## Terms
|
|
5
|
+
|
|
6
|
+
You decide what to test. The tools give you the diff and the existing tests; they do not choose tests for you.
|
|
7
|
+
|
|
8
|
+
A **change** is one thing the pull request should make happen, or reject, for a user or a caller. Say on each change whether it is on the API, on a page, or both.
|
|
9
|
+
|
|
10
|
+
A **behaviour** is one rule about one endpoint or one page. One change can carry two behaviours, one on the API and one on the page. A test may prove several behaviours. Every behaviour has at least one test that proves it. All the rejections of one endpoint's input are one test with one case each. Declare on each change the inputs that prove it: what the route must accept and what it must reject.
|
|
11
|
+
|
|
12
|
+
## The procedure
|
|
13
|
+
|
|
14
|
+
Do the steps in this order.
|
|
15
|
+
|
|
16
|
+
1. **Read the pull request title and description.** If they name a requirements file, read it too.
|
|
17
|
+
2. **Read the whole diff.** Run `git diff <base>...HEAD` in the repository path. No tool returns the diff text. Page it if it is large.
|
|
18
|
+
3. **Write the changes.** List every change, one line each, with a short id and where you read it. Write the list in your reply before you go on.
|
|
19
|
+
Keep each line through the rest of the procedure. Do not fold a change into another one or drop it because no test covers it.
|
|
20
|
+
For each edit in the diff, write one line: what it makes different for a user or a caller.
|
|
21
|
+
For each input a request takes, declare one case with a value the request must reject. Declare it even when the code does not reject that value today.
|
|
22
|
+
If a request must reject a value because of a record that already exists, declare that case too.
|
|
23
|
+
A request that names a record by id, in the path, in a query parameter, or in the body, must reject a record that does not exist or does not belong to the parent.
|
|
24
|
+
A record that belongs to another user is its own case, even when the answer is the same.
|
|
25
|
+
4. **Find where each change is served.** Read the code that declares routes and pages, and write each route's full path with its mount prefix. Follow the callers of a changed file that has no route of its own to the endpoint or page that runs it. Read the code that writes each stored value the new code reads; any rule on that value is a rejection to list.
|
|
26
|
+
5. **Read the existing tests that reach a change.** The analysis lists the repository's test files. Read the ones that import a changed file, call a changed route, or open a changed page.
|
|
27
|
+
6. **Group the changes into behaviours and decide each.** A planned test names every change it covers. A change gets no test only when a test already in the repository proves it; the size of the edit or the kind of file is never a reason. A change no behaviour needs gets one sentence that says why.
|
|
28
|
+
If a state comes from time passing, create the record with the nearest allowed deadline and wait for it.
|
|
29
|
+
7. **Walk each page behaviour once, as its test will run.** Start at login, do the steps of the behaviour, run `browser_blueprint` on each page you use, and export the trace when the flow ends. Name only elements from those captures. Do not try other values or read messages; the recording is the test.
|
|
30
|
+
8. **Declare each planned test.** The tool schema says what goes in each field. A test that expects a rejection sends an accepted request first and asserts it succeeds. Two planned tests on one endpoint each say how they differ.
|
|
31
|
+
9. **Register the whole plan in one call to `skyramp_register_test_plan`.**
|
|
32
|
+
10. **Answer each objection, or change the plan and register it again.**
|
|
33
|
+
An answer that says a state cannot be produced says what you tried.
|
|
34
|
+
11. **Stop when every objection has an answer.** Disagreeing in the answer closes it too.
|
|
35
|
+
|
|
36
|
+
Then write the tests. The generation instructions say how.
|
|
37
|
+
|
|
38
|
+
## Decisions the checks leave to you
|
|
39
|
+
|
|
40
|
+
- **Requirement conflict.** Only a file the title or description names is a requirement source; a generated file or a URL is not. Do not search for other sources. Judge an edited requirements file on its new text. If the file is unchanged and the description presents the new behaviour as intended, the file is out of date, not in conflict. Report a conflict only when the named file states a behaviour and the code does not do it.
|
|
41
|
+
- **Removed element.** If the diff removes an element from a page that still renders, plan a test that asserts it is absent. If it removes a whole component, route, or page, delete the tests that covered it.
|
|
42
|
+
- **Reaching a screen after login.** If a control in the application leads to the screen, use the control. If no control leads to it, call `browser_navigate` with its URL once and continue in the same session.
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Testbot task 1: the v2 parts
|
|
2
|
+
|
|
3
|
+
The blueprint citation rule for a UI recommendation, and the guardrail that
|
|
4
|
+
stops a follow-up run from generating more tests.
|
|
5
|
+
|
|
6
|
+
## Blueprint citation
|
|
7
|
+
|
|
8
|
+
{uiGroundingStep}. **Blueprint Citation Invariant** (UI entries of `newTestsCreated` only). Every UI
|
|
9
|
+
element you name comes from an element a blueprint of this run actually captured. Copy the values the
|
|
10
|
+
capture gives and invent none — it omits `testId`, `stableId` and `contextText` for an element that
|
|
11
|
+
has no such value, so omit them too. The report tool's schema states each field's shape and which
|
|
12
|
+
entries may carry it.
|
|
13
|
+
|
|
14
|
+
Judgment the schema cannot make for you:
|
|
15
|
+
|
|
16
|
+
- **One element or several.** One when the test has a single dominant target — a click, a type, a
|
|
17
|
+
single visibility check, which is most tests. Several when it verifies elements together: a render
|
|
18
|
+
state, a workflow whose action is in one element and whose result is in another, a form fill. When
|
|
19
|
+
there is no single focus, anchor on the page heading or the most stable element on the page.
|
|
20
|
+
- **A negative test still cites a real capture.** Ground `elements.items` against a page where the
|
|
21
|
+
element DOES render, so the citation can be confirmed.
|
|
22
|
+
- **A removal guard is the one entry not lifted from a capture.** The element the PR removed renders
|
|
23
|
+
nowhere, so no blueprint holds it. Cite it from `uiContext.removedElements` — `testId` for a
|
|
24
|
+
`data-testid`, otherwise name the `attribute="value"` pair in `reasoning` and leave `testId` null —
|
|
25
|
+
take `role` and `accessibleName` from the deleted JSX in the diff, set `elements.pageUrl` to the
|
|
26
|
+
page you established for it, and prefix `reasoning` with `[removed-element]`.
|
|
27
|
+
- **`description` and `reasoning` are complementary, not two spellings of one sentence.**
|
|
28
|
+
`description` walks through what the test does; `reasoning` says in one sentence what it verifies
|
|
29
|
+
and why. The report schema says how to name a UI element in either.
|
|
30
|
+
|
|
31
|
+
Before submitting, check that every element name in `reasoning` matches an entry's `accessibleName`
|
|
32
|
+
exactly and every backticked identifier comes from an entry's `testId` or `stableId`. If one does
|
|
33
|
+
not, re-capture or drop that test. The `[no-blueprint-data]` marker and the two kinds of absence it
|
|
34
|
+
does and does not cover are in the UI recommendation grounding section of the execution plan.
|
|
35
|
+
|
|
36
|
+
## Follow-up generation guardrail
|
|
37
|
+
|
|
38
|
+
- If the prompt requests adding, extending, or generating any test — including "all", "more", a count, or a named scenario → STOP EARLY. Call `skyramp_submit_report` with an empty array for `newTestsCreated` and a single entry in `issuesFound` with description set to EXACTLY this template: "Testbot generated every test this change warranted in its first run. The previous report's objections and their answers list what was deliberately not tested and why. Follow-up requests for more tests are not generated." Do NOT add any other text and do NOT paraphrase this template.
|
|
39
|
+
|
|
40
|
+
## Analyze the change
|
|
41
|
+
|
|
42
|
+
{analyzeStep}. Call `skyramp_analyze_changes` with `repositoryPath`: "{repositoryPath}", `scope`: "branch_diff"{analyzeCountArgs}{baseBranchArg}{prNumberArg}{testsRepoDirArg}.
|
|
43
|
+
|
|
44
|
+
**Follow all instructions returned by `skyramp_analyze_changes`.**{uiCredentialsNote}
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
**Feature context check:** After you capture a blueprint, 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 cannot reach the right context from the diff and the workspace config, leave the planned test's element list empty, name the page you opened, and note it in `issuesFound`.
|
|
48
|
+
|
|
49
|
+
**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 {generateTask} until an analysis succeeds: it writes the state file every later tool reads.
|
|
50
|
+
|
|
51
|
+
## Log in before capturing
|
|
52
|
+
|
|
53
|
+
Log in once via the credentials in your <ui-credentials> context before you navigate to any page you capture.
|
|
54
|
+
|
|
55
|
+
## Multi-repo context
|
|
56
|
+
|
|
57
|
+
**MULTI-REPO CONTEXT (MANDATORY).** This run includes {relatedRepoCount} related {repoWord} listed in the `<related_repositories>` block below, each with an explicit `repository` (`owner/repo`), `path`, and `base_branch`. Use the `repository` value verbatim — do NOT infer it from git remotes or paths. You MUST analyze EACH related repository — exactly one `skyramp_analyze_changes` call per listed repo ({relatedRepoCount} {callWord}), in addition to the primary call in step {analyzeStep}.
|
|
58
|
+
|
|
59
|
+
**Run the primary call (step {analyzeStep}) FIRST, then the related repos in listed order — not in parallel.** All calls in this run automatically share ONE run-scoped state file — you do NOT pass a state-file path; setting `repository` is enough. The primary writes its root section; each related repo's call upserts its own section into that same file. Concurrent calls would race on the shared file, so they must be sequential. For each related repo:
|
|
60
|
+
- **({registerServicesStep})** Register its services into the **single unified workspace** — do NOT write a `.skyramp/workspace.yml` into the related repo (it is read-only context, and a per-repo file would need its own PR). The unified workspace always lives in the **primary repo** (where the testbot workflow is installed): `{repositoryPath}`{testRepoExclusionNote}. Steps: call `skyramp_init_scan` with `workspacePath`: the related repo's `path` to DISCOVER its services, then call `skyramp_init_workspace` with `workspacePath`: "{repositoryPath}" (the PRIMARY repo, NOT the related repo's path{testRepoExclusionShort}), `merge`: true, the `scanToken`, and the discovered services — each with its `repository` field set to that repo's `repository` value from the block. This upserts the related repo's services into the one unified `.skyramp/workspace.yml` (services are keyed by the composite of `repository` + `serviceName`).
|
|
61
|
+
- **({analyzeRepoStep})** Then call `skyramp_analyze_changes` with that repo's `path` (as `repositoryPath`), `scope`: "branch_diff", and `repository`: that repo's `repository` value. Passing `repository` stores this analysis as a section within the one run-scoped state file (the file is reused automatically across calls — do NOT pass any state-file path). Pass `baseBranch` only when the repo's `base_branch` attribute names a concrete branch; when `base_branch` is `auto-detect`, OMIT `baseBranch` and let the tool detect the repo's default branch.
|
|
62
|
+
- **({onFailureStep})** If analysis of a related repo fails (e.g. workspace init or diff error), record a one-line `issuesFound` note and CONTINUE — a missing related repo must not block the primary analysis.
|
|
63
|
+
Keep ALL returned diffs and recommendations from every repo in your working context. **Correlate** cross-repo changes when forming recommendations and the business case — e.g. an API contract changed in one repo and consumed by another, a request/response shape that must stay compatible across the boundary.
|
|
64
|
+
|
|
65
|
+
**One state file, per-repo sections.** There is exactly ONE state file for the whole run (created automatically and reused across calls). Each `skyramp_analyze_changes` call writes its repo's section into it (keyed by `repository`); pass `primaryRepository: {primaryRepo}` on every one of those calls too, so the root section is the primary's whichever call runs first. When you maintain/act on any repo's tests — `skyramp_analyze_test_health`, `skyramp_actions`, `skyramp_execute_test` — pass that repo's `repository` (`owner/repo`) as the `repository` argument alongside the `stateFile` path returned by `skyramp_analyze_changes`, so the tool reads/writes that repo's section. The primary repo's `repository` is `{primaryRepo}`; pass it for the primary repo's tests just as you do for related repos.
|
|
66
|
+
|
|
67
|
+
**Cross-repo test generation ({generateTask} spans all repos).** Draft your planned tests from the analysis of the primary AND every related repo together, and register them as ONE plan. When you generate a test for a related repo's endpoint:
|
|
68
|
+
- **Execute it only if that repo's service is already running and reachable.** The workflow's setup may have started multiple services; before generating an API test for a related repo, confirm its `base_url` (from that repo's workspace/Execution Plan) responds. If the service is unreachable, still GENERATE the test but mark its `testResults` status as `Skipped` with details "service not running in this run" — do NOT count an unreachable service as a failure.
|
|
69
|
+
- **Write the test file into that service's own `testDirectory`** — the one declared for the service in the unified workspace.yml (the related repo's services were registered there in {registerServicesRef}, each with its `repository`). The `testDirectory` is interpreted relative to the **single delivery root** (the configured test repo if set, otherwise the primary repo), so all generated tests are delivered together by the existing single-target delivery. Do NOT invent a per-source-repo subdirectory, and do NOT write into the related repo's own checkout — it is read-only context. (If two repos happen to declare the same `testDirectory`, their files coexist there; the `repository` field on each report item — below — is what attributes ownership, not the path.)
|
|
70
|
+
- **Set the `repository` field** (`owner/repo`) on every such `newTestsCreated` / `testResults` item so the report attributes it to the originating repo (see Report Guidelines).
|
|
71
|
+
|
|
72
|
+
## Code review
|
|
73
|
+
|
|
74
|
+
{codeReviewStep}. **Code review:** Find the logic bugs in the code that this change touches. Read the implementation of each changed endpoint: the route handler, and the functions that it calls to read or write data. For a changed screen, read the component and the functions that it calls. Read these files even when the diff does not contain them — a defect often sits in the code that the change depends on. Report each objection in `issuesFound` with a severity, and say which file and line holds it. Common patterns to flag:
|
|
75
|
+
- Computed fields not recalculated after mutation (e.g. `total_amount` unchanged after items are added/removed)
|
|
76
|
+
- Incomplete CRUD: create without cleanup, update that adds new records without removing old ones
|
|
77
|
+
- Missing input validation on new endpoints
|
|
78
|
+
- Frontend rendering errors visible in the code (e.g. invalid props, missing required attributes)
|
|
79
|
+
- Incorrect arithmetic in business logic (discount calculations, price aggregation)
|
|
80
|
+
Log each objection in `issuesFound` with a `severity` (critical/high/medium/low). These bugs should inform your test design in {generateTask}.
|
|
81
|
+
|
|
82
|
+
**In the same pass, check the code against what the PR says it does**, following the full rule and its four checks under "The decisions that no check makes" in the planning procedure.
|