@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
|
@@ -1,12 +1,24 @@
|
|
|
1
1
|
import { isContractConsumerModeEnabled } from "../../utils/featureFlags.js";
|
|
2
|
+
import { sectionBody } from "../promptAssets.js";
|
|
3
|
+
import { readPromptAsset } from "../promptAssets.js";
|
|
4
|
+
import { fillPlaceholders } from "../../recommendation/verifierContracts.js";
|
|
2
5
|
import { resolveServiceDetailsRef } from "../../utils/utils.js";
|
|
3
|
-
import {
|
|
6
|
+
import { getAuthScheme, isAuthorizationHeaderName } from "../../utils/workspaceAuth.js";
|
|
4
7
|
// Cached at module-load — flags are process-wide and cannot change per call.
|
|
5
8
|
const CONSUMER_MODE_ENABLED = isContractConsumerModeEnabled();
|
|
6
9
|
const SERVICE_REFS = resolveServiceDetailsRef();
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
+
// The instruction text lives in `plugin/prompts/generate-tests/`; this file reads
|
|
11
|
+
// it back.
|
|
12
|
+
// One read at module load: the files ship with the package and cannot change
|
|
13
|
+
// under a running server.
|
|
14
|
+
const GENERATION_MD = readPromptAsset("generate-tests/generation.md");
|
|
15
|
+
// One sentence the run chooses between — the workspace auth shape, the contract
|
|
16
|
+
// modes this build ships. Each half is its own section rather than a ternary
|
|
17
|
+
// inside the sentence, so the whole instruction stays readable in the markdown.
|
|
18
|
+
const TOOL_WORKFLOW_VARIANTS_MD = readPromptAsset("generate-tests/tool-workflow-variants.md");
|
|
19
|
+
function variant(heading, values) {
|
|
20
|
+
return fillPlaceholders(sectionBody(TOOL_WORKFLOW_VARIANTS_MD, heading), values);
|
|
21
|
+
}
|
|
10
22
|
/**
|
|
11
23
|
* Error string emitted by skyramp_integration_test_generation when both
|
|
12
24
|
* an explicit authHeader and a workspace api.authType are passed simultaneously.
|
|
@@ -15,51 +27,24 @@ export const MAX_CRITICAL_TESTS = 3;
|
|
|
15
27
|
*/
|
|
16
28
|
export const AUTH_CONFLICT_ERROR_MSG = "Auth header and auth type cannot be supported at the same time.";
|
|
17
29
|
export function buildArchitectPreamble(isDiffScope) {
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
}
|
|
28
|
-
return `You are acting as a Skyramp Integration Architect. You will receive a full repository analysis — all endpoints, source code interactions, and existing tests. 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.
|
|
29
|
-
|
|
30
|
-
Your task:
|
|
31
|
-
1. **Produce a comprehensive test recommendation catalog** grouped by test type (E2E → UI → Integration → Contract), ranked by production risk within each type
|
|
32
|
-
2. **Present each recommendation with a complete, ready-to-use Skyramp tool call** — fill in all field names, endpoint URLs, request shapes, and auth parameters from source code so the catalog is immediately actionable
|
|
33
|
-
3. **Do not call any generation tools** — your output is the catalog itself; it is executed on demand
|
|
34
|
-
|
|
35
|
-
Replace every \`<…from source>\` placeholder with actual values before presenting. Do not invent values — read the source file if a value is unclear.`;
|
|
30
|
+
// One preamble with two filled-in values, rather than a near-identical copy
|
|
31
|
+
// per scope: only the input it describes and the first task line differ.
|
|
32
|
+
return fillPlaceholders(sectionBody(GENERATION_MD, "## Architect preamble"), {
|
|
33
|
+
scopeInput: isDiffScope
|
|
34
|
+
? "a branch diff — changed endpoints, source code interactions, and existing tests"
|
|
35
|
+
: "a full repository analysis — all endpoints, source code interactions, and existing tests",
|
|
36
|
+
scopeTask: isDiffScope
|
|
37
|
+
? "Recommend AND generate tests for this PR's changes"
|
|
38
|
+
: "Decide which tests this repository is missing",
|
|
39
|
+
});
|
|
36
40
|
}
|
|
37
41
|
export function buildContextFetchingGuidance(sessionId) {
|
|
38
42
|
if (!sessionId)
|
|
39
43
|
return "";
|
|
40
|
-
return
|
|
41
|
-
## Execution Plan Context
|
|
42
|
-
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.
|
|
43
|
-
</context_fetching_protocol>`;
|
|
44
|
+
return readPromptAsset("generate-tests/context-fetching.md").trim();
|
|
44
45
|
}
|
|
45
46
|
export function buildReasoningProtocol() {
|
|
46
|
-
return
|
|
47
|
-
## Parameter Grounding Rule
|
|
48
|
-
Before each GENERATE tool call, confirm WHERE each key value comes from:
|
|
49
|
-
|
|
50
|
-
- **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.
|
|
51
|
-
- **endpointURL** → workspace \`baseUrl\` + endpoint path (both required — never path alone)
|
|
52
|
-
- **authHeader / authScheme** → workspace config or OpenAPI \`securitySchemes\`
|
|
53
|
-
- **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.
|
|
54
|
-
- **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.
|
|
55
|
-
|
|
56
|
-
## Ranking Rule
|
|
57
|
-
For each GENERATE item, include one sentence in your output (before the tool calls) stating the specific bug or failure it targets — derived from \`bugCatchingTarget\` or your source-code reading. Example: "Targets: order total miscalculation — total_amount = sum(item.price × item.quantity) should recompute when items array changes."
|
|
58
|
-
|
|
59
|
-
If \`bugCatchingTarget\` is empty for a GENERATE item, derive it from source code before including the item. A GENERATE slot without a specific bug target belongs in ADDITIONAL.
|
|
60
|
-
|
|
61
|
-
If a value cannot be sourced, read the relevant source file before calling the tool. Do not proceed with invented values.
|
|
62
|
-
</reasoning_protocol>`;
|
|
47
|
+
return readPromptAsset("generate-tests/reasoning-protocol.md").trim();
|
|
63
48
|
}
|
|
64
49
|
function serializeAuthCallParams(params) {
|
|
65
50
|
const parts = [`authHeader: "${params.authHeader}"`];
|
|
@@ -71,177 +56,26 @@ function serializeAuthCallParams(params) {
|
|
|
71
56
|
}
|
|
72
57
|
return parts.join(", ");
|
|
73
58
|
}
|
|
74
|
-
/**
|
|
75
|
-
*
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
* source of truth — so this file no longer maintains its own slug→scheme table.
|
|
79
|
-
*/
|
|
80
|
-
export function getAuthSnippets(authHeaderValue, authType, explicitScheme) {
|
|
81
|
-
if (!authHeaderValue) {
|
|
82
|
-
return { authSchemeSnippet: "", authTokenSnippet: "" };
|
|
83
|
-
}
|
|
84
|
-
// Only Authorization headers carry an authScheme prefix.
|
|
85
|
-
if (!isAuthorizationHeaderName(authHeaderValue)) {
|
|
86
|
-
return { authSchemeSnippet: "", authTokenSnippet: "" };
|
|
87
|
-
}
|
|
88
|
-
if (authType && authType !== WorkspaceAuthType.None) {
|
|
89
|
-
// Resolve via the canonical workspaceAuth mapping, passing explicit scheme if set.
|
|
90
|
-
const wsType = authType;
|
|
91
|
-
const scheme = getAuthScheme(wsType, explicitScheme);
|
|
92
|
-
// Use !== undefined so intentionally empty scheme ("" = raw token, no prefix) is preserved.
|
|
93
|
-
if (scheme !== undefined) {
|
|
94
|
-
return { authSchemeSnippet: `, authScheme: "${scheme}"`, authTokenSnippet: "" };
|
|
95
|
-
}
|
|
96
|
-
}
|
|
97
|
-
return { authSchemeSnippet: ', authScheme: "<scheme e.g. Bearer, Basic, Token or empty>"', authTokenSnippet: "" };
|
|
59
|
+
/** Read whole, and by both callers: it is one instruction with no run fact in
|
|
60
|
+
* it, so it has one home in the skill rather than a copy here. */
|
|
61
|
+
export function buildPathParamGuidance() {
|
|
62
|
+
return readPromptAsset("generate-tests/path-parameters.md").trim();
|
|
98
63
|
}
|
|
99
|
-
export const PATH_PARAM_UUID_GUIDANCE = `**Path parameters:** keep the placeholder in \`endpointURL\` (e.g. \`/coupons/{coupon_id}\`). ` +
|
|
100
|
-
`Pass the value via \`pathParams\` (e.g. \`coupon_id=<random-uuid-v4>\`). ` +
|
|
101
|
-
`Use example values from the OpenAPI schema if available; otherwise generate a fresh random UUID v4 — not all-zeros or repeated-digit patterns.`;
|
|
102
64
|
export function buildTestPatternGuidelines() {
|
|
103
|
-
return
|
|
104
|
-
|
|
105
|
-
#### Tier 1 — Base Patterns
|
|
106
|
-
- CRUD lifecycle per resource group (Create → Read → Update → Delete)
|
|
107
|
-
- Auth flow (Register → Login → Access protected → Token refresh → Logout)
|
|
108
|
-
- Pagination & filtering (boundary values, empty results, large page sizes)
|
|
109
|
-
- Error responses (400, 401, 403, 404, 409, 422 — each with a specific trigger)
|
|
110
|
-
**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.
|
|
111
|
-
|
|
112
|
-
#### Tier 2 — Code-Informed Patterns (higher value, look for these in source code)
|
|
113
|
-
- **Middleware chains**: If auth/rate-limit/logging middleware exists, test the chain (e.g., rate limit hit → auth still checked → correct error returned)
|
|
114
|
-
- **N+1 query risk**: If list endpoints join related data (e.g., orders with products), test with large datasets
|
|
115
|
-
- **State machines**: If resources have status transitions (draft→published→archived), test invalid transitions (e.g., archived→draft should fail)
|
|
116
|
-
- **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.
|
|
117
|
-
- **Race conditions**: If concurrent writes are possible (inventory deduction, counter increment), test concurrent requests
|
|
118
|
-
- **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)
|
|
119
|
-
- **Mutation with collection modification**: If PUT/PATCH endpoints accept arrays of child items (e.g., order line items, cart products, invoice entries), test adding/removing items and verify that derived totals (e.g., total_amount, subtotal, item_count) are recalculated correctly. This is the most common source of user-reported bugs — always prioritize it for GENERATE over simple field-update tests.
|
|
120
|
-
The PATCH/PUT request body should include the child collection array field(s) defined for that endpoint (e.g., "items" with foreign-key references like "product_id" and a quantity field) chained from prior POST responses. A PATCH that only sends metadata fields (e.g., discount_type, status, notes) without modifying the child collection is NOT a valid mutation-recalc test — it will pass even when the item/total logic is broken. Before writing assertions, inspect the source code or OpenAPI spec to identify (1) the actual child collection field name and its foreign-key/quantity/price sub-fields, and (2) how derived totals are calculated (including any discounts, taxes, or fees). Then assert: the child foreign-key fields match chained IDs, quantities match sent values, and totals match the computation from the source code
|
|
121
|
-
- **Webhook/event side effects**: If endpoints trigger async operations, test that side effects occur (e.g., POST /orders triggers notification)
|
|
122
|
-
- **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)
|
|
123
|
-
- **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)
|
|
124
|
-
- **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)`;
|
|
65
|
+
return sectionBody(GENERATION_MD, "## Test pattern guidelines");
|
|
125
66
|
}
|
|
126
67
|
export function buildTestQualityCriteria() {
|
|
127
|
-
return
|
|
128
|
-
|
|
129
|
-
**Integration tests** should demonstrate cross-resource data flow — step A creates data
|
|
130
|
-
that step B depends on (e.g., create product → create order referencing that product's ID →
|
|
131
|
-
verify order contains correct product). Single-resource CRUD alone is not an integration test.
|
|
132
|
-
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.
|
|
133
|
-
When a PUT/PATCH updates a resource with child collections (e.g., order items), the request body
|
|
134
|
-
MUST include the child array with foreign-key references chained from prior steps — and assertions MUST
|
|
135
|
-
verify the actual child items in the response (product_id, quantity, unit_price), not just
|
|
136
|
-
top-level metadata like discount or status.
|
|
137
|
-
|
|
138
|
-
**Contract tests** (single-step) are the right choice for: error-handling scenarios on a single
|
|
139
|
-
endpoint (e.g., PATCH/GET/DELETE a nonexistent resource → 404, POST with invalid payload → 422),
|
|
140
|
-
validation boundary checks, and any test that exercises one endpoint's API contract in isolation.
|
|
141
|
-
Do NOT add setup steps just to avoid hardcoding an ID — use a realistic hardcoded nonexistent ID
|
|
142
|
-
(e.g., 99999 or a random UUID) and keep it a single-step contract test.
|
|
143
|
-
|
|
144
|
-
**E2E tests** should follow realistic user journeys end-to-end: browse products → search →
|
|
145
|
-
add to cart → checkout. Verify that frontend actions trigger the correct API calls and
|
|
146
|
-
that the UI reflects backend state.
|
|
147
|
-
|
|
148
|
-
**UI tests** should exercise component behavior and interaction flows: fill form → validate
|
|
149
|
-
inputs → submit → see confirmation. Include visual state changes (loading, error, empty)
|
|
150
|
-
and accessibility checks.`;
|
|
68
|
+
return sectionBody(GENERATION_MD, "## Test quality criteria");
|
|
151
69
|
}
|
|
152
|
-
export function buildGenerationRules(
|
|
153
|
-
return
|
|
154
|
-
|
|
155
|
-
**Available test types:** integration, contract, E2E, UI. **No smoke or fuzz tests.**
|
|
156
|
-
Choose based on what adds the most value for this PR's changes.
|
|
157
|
-
|
|
158
|
-
${CONSUMER_MODE_ENABLED ? `**Contract test mode — signal-based selection:**
|
|
159
|
-
- **Consumer contract** (\`consumerMode: true\`): Look for outbound HTTP client code (fetch, axios, httpx, requests, http.Client), service client classes, or calls to external base URLs. If an endpoint's implementation makes downstream calls, that downstream boundary is a consumer contract test candidate.
|
|
160
|
-
- **Provider contract** (\`providerMode: true\`): Look for new or modified endpoint handlers, route changes, or response shape modifications. If the diff adds/changes an endpoint this service owns, that is a provider contract test candidate.
|
|
161
|
-
- **Both modes** (\`providerMode: true, consumerMode: true\`) — produces the same output as omitting both flags (generates provider and consumer contract tests). Use when the diff contains BOTH provider signals (new/modified endpoint handlers) AND consumer signals (outbound HTTP client calls to another service).` : `**Contract tests — provider-only:**
|
|
162
|
-
Only provider-side contract tests are supported. Recommend a contract test (\`providerMode: true\`) when the diff adds or modifies an endpoint handler, route, or response shape that this service owns.`}
|
|
163
|
-
|
|
164
|
-
**Scenario fidelity:** Every workflow scenario should reflect the actual resource
|
|
165
|
-
relationships in the code. If the pre-drafted scenarios don't match the real data model,
|
|
166
|
-
replace them with accurate ones.
|
|
167
|
-
${isUIOnlyPR ? `
|
|
168
|
-
**UI-only PR** — no backend changes. UI tests are most relevant.
|
|
169
|
-
Use Playwright browser tools to auto-record traces and generate UI tests.
|
|
170
|
-
` : `
|
|
171
|
-
When no Playwright trace exists, use the Playwright browser tools (\`browser_navigate\`,
|
|
172
|
-
\`browser_click\`, etc.) to record a trace, then export via \`skyramp_export_zip\` for UI tests.
|
|
173
|
-
`}
|
|
174
|
-
`;
|
|
70
|
+
export function buildGenerationRules() {
|
|
71
|
+
return `${sectionBody(GENERATION_MD, "## Generation rules")}\n`;
|
|
175
72
|
}
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
Before
|
|
179
|
-
1. **Count**: Total recommendation count equals the total you stated in your Budget Plan (at most ${topN}). Your GENERATE + ADDITIONAL counts must match the split you committed to — neither fewer nor padded.
|
|
180
|
-
2. **Distinct paths**: Each GENERATE item targets a distinct code path — no two share the same HTTP method + endpoint + expected status.
|
|
181
|
-
3. **Auth parameters are consistent** across all tool calls (same authHeader and authScheme).
|
|
182
|
-
4. Every endpointURL includes both the base URL and the path (not just the base, e.g. \`http://host/api/v1/orders/{id}\`).
|
|
183
|
-
5. **All \`<from source>\` placeholders** you received have been replaced with actual values derived from source code — no \`<...>\` remain in your output.
|
|
184
|
-
6. **Real request shapes**: requestBody for POST/PUT/PATCH uses actual field names from source (not \`{}\`). GET search/filter uses \`queryParams\`, not \`requestBody\`.
|
|
185
|
-
7. **scenarioFile**: \`skyramp_integration_test_generation\` uses the exact \`filePath\` returned by \`skyramp_batch_scenario_test_generation\` — not a guessed or hardcoded filename.
|
|
186
|
-
8. **bugCatchingTarget**: Every GENERATE integration test that targets a business rule, formula, or constraint has a non-empty \`bugCatchingTarget\`.
|
|
187
|
-
9. **Foreign-key chaining**: In multi-step integration tests, path params sourced from a prior step's response (e.g. \`order_id\` from step 1) use \`chainsFrom\` — not hardcoded IDs.
|
|
188
|
-
10. **Concrete scenario names**: No GENERATE item uses a placeholder name ending in a numeric suffix (e.g. \`ui-test-for-changed-component-1\`, \`ui-test-from-trace-2\`). Derive the name from the actual changed component or flow: if the diff touches \`LinkCard.tsx\`, the scenario name should be \`link-card-pin-toggle\` or \`link-card-edit-description\`, not \`ui-test-for-changed-component-1\`. The changed file list is available above — use it.
|
|
189
|
-
11. **Issue coverage**: If \`<bug_found>\` blocks exist from Step ${codeReviewStepLabel} (Code Review), verify that every promoted flaw (HIGH or CRITICAL) has at least one GENERATE item directly targeting it (its pass/fail outcome depends on whether that bug exists). If a promoted flaw lacks a dedicated GENERATE item, promote or create one before proceeding. HIGH/CRITICAL flaws past the promotion bound Step ${codeReviewStepLabel} sets should appear in ADDITIONAL at highest priority.
|
|
190
|
-
12. **Code Review completeness**: Did you produce a \`<function_review>\` block for EVERY changed function/handler in Step ${codeReviewStepLabel}? If any function is missing a review, you skipped the correctness analysis for it. Go back and complete it before finalizing.
|
|
191
|
-
13. **Requirement coverage**: If \`<requirement_conflict>\` blocks exist from Step ${codeReviewStepLabel} — a requirement the PR title/description (or a requirements file it references) states, which the implemented behavior contradicts — verify every promoted one has its OWN GENERATE item, category \`requirement_conflict\`, asserting the stated requirement and therefore failing on the current code. Requirement conflicts take the first slots of the promotion bound Step ${codeReviewStepLabel} sets, ahead of the \`<bug_found>\` flaws, so a run with one finding of each kind carries both tests. Where no such test is recordable, a VERIFY-style entry in \`additionalRecommendations\` ("the description and the implementation disagree — needs a developer decision, not a test edit") satisfies this instead. Every requirement conflict also has an \`issuesFound\` entry at severity \`high\` or above, attributed to its source. A conflict reported only as prose, with a passing test that asserts what the code does, fails this check.
|
|
192
|
-
</verification>`;
|
|
73
|
+
/** The checks on the test file itself, rendered at the moment it is written. */
|
|
74
|
+
export function buildFinishChecks() {
|
|
75
|
+
return sectionBody(GENERATION_MD, "## Before you finish a test");
|
|
193
76
|
}
|
|
194
|
-
export function
|
|
195
|
-
return
|
|
196
|
-
<example index="1" type="integration_recommendation">
|
|
197
|
-
<thinking>
|
|
198
|
-
**Parameter grounding**:
|
|
199
|
-
- baseURL: "http://localhost:8000" (workspace api.baseUrl)
|
|
200
|
-
- steps[0].requestBody fields "name", "price": ProductCreate schema fields (src/models/product.py)
|
|
201
|
-
- steps[1].requestBody "product_id": foreign key to products — chained from step 0 response id
|
|
202
|
-
- steps[1].requestBody "quantity": OrderCreate schema field (src/models/order.py)
|
|
203
|
-
- responseBody "total_amount": 89.97 = 29.99 × 3 — from order total formula (src/services/order_service.py: total = sum(item.price * item.quantity))
|
|
204
|
-
- authHeader/authScheme: workspace config (Authorization / Bearer)
|
|
205
|
-
</thinking>
|
|
206
|
-
|
|
207
|
-
**#1 — GENERATE** | integration | business_rule | new
|
|
208
|
-
Scenario: orders-create-with-product-total-calc (3 steps)
|
|
209
|
-
1. POST /api/v1/products → 201: Create product with known price
|
|
210
|
-
2. POST /api/v1/orders → 201: Create order referencing product_id from step 1, quantity=3
|
|
211
|
-
3. GET /api/v1/orders/{order_id} → 200: Verify total_amount = 29.99 × 3 = 89.97
|
|
212
|
-
bugCatchingTarget: "total_amount = sum(item.price × item.quantity) — wrong if multiplication is skipped or items list is ignored"
|
|
213
|
-
Tool calls:
|
|
214
|
-
skyramp_batch_scenario_test_generation({ scenarioName: "orders-create-with-product-total-calc", destination: "localhost", baseURL: "http://localhost:8000", authHeader: "Authorization", authScheme: "Bearer", steps: [
|
|
215
|
-
{ method: "POST", path: "/api/v1/products", statusCode: 201, requestBody: "{\"name\": \"Widget-1713000000\", \"price\": 29.99}" },
|
|
216
|
-
{ method: "POST", path: "/api/v1/orders", statusCode: 201, requestBody: "{\"product_id\": \"chained\", \"quantity\": 3}" },
|
|
217
|
-
{ method: "GET", path: "/api/v1/orders/{order_id}", statusCode: 200, responseBody: "{\"id\": \"chained\", \"total_amount\": 89.97, \"items\": [{\"product_id\": \"chained\", \"quantity\": 3, \"unit_price\": 29.99}]}" }
|
|
218
|
-
] })
|
|
219
|
-
skyramp_integration_test_generation({ scenarioFile: "<filePath returned by skyramp_batch_scenario_test_generation above>" })
|
|
220
|
-
Reasoning: Catches a broken total calculation before it ships — the most common source of order-related bug reports.
|
|
221
|
-
</example>
|
|
222
|
-
|
|
223
|
-
<example index="2" type="contract_recommendation">
|
|
224
|
-
<thinking>
|
|
225
|
-
**Parameter grounding**:
|
|
226
|
-
- endpointURL: "http://localhost:8000/api/v1/products/{product_id}" (workspace baseUrl + path from endpoint listing)
|
|
227
|
-
- method: "DELETE" (route definition, uppercase)
|
|
228
|
-
- pathParams "product_id=<random-uuid-v4>": hardcoded non-existent ID — no setup step needed for a 404 test; use a fresh UUID v4, not all-zeros
|
|
229
|
-
- authHeader/authScheme: workspace config (Authorization / Bearer)
|
|
230
|
-
- No requestData — DELETE carries no body
|
|
231
|
-
</thinking>
|
|
232
|
-
|
|
233
|
-
**#2 — GENERATE** | contract | error_handling | new
|
|
234
|
-
DELETE /api/v1/products/{product_id} → 404
|
|
235
|
-
Tool: skyramp_contract_test_generation({ endpointURL: "http://localhost:8000/api/v1/products/{product_id}", method: "DELETE", authHeader: "Authorization", authScheme: "Bearer", pathParams: "product_id=<random-uuid-v4>" })
|
|
236
|
-
Reasoning: Catches a missing 404 guard on DELETE — verifies the handler returns 404 for non-existent resources rather than a 500 or silent no-op.
|
|
237
|
-
</example>
|
|
238
|
-
|
|
239
|
-
<example index="3" type="additional_recommendation">
|
|
240
|
-
#5 [ADDITIONAL] | integration | security_boundary | existing
|
|
241
|
-
Scenario: orders-unauthorized-cross-user-access (POST /api/v1/orders → GET /api/v1/orders/{order_id} as different user → 403)
|
|
242
|
-
Validates: Cross-user isolation — user B cannot read user A's orders.
|
|
243
|
-
</example>
|
|
244
|
-
</examples>`;
|
|
77
|
+
export function buildVerificationChecklist() {
|
|
78
|
+
return sectionBody(GENERATION_MD, "## Verification checklist");
|
|
245
79
|
}
|
|
246
80
|
export function buildToolWorkflows(authHeaderValue, authTypeValue = "", explicitScheme, enrichStepLabel = "2") {
|
|
247
81
|
const isAuthorizationHeader = isAuthorizationHeaderName(authHeaderValue);
|
|
@@ -249,13 +83,7 @@ export function buildToolWorkflows(authHeaderValue, authTypeValue = "", explicit
|
|
|
249
83
|
let authGuidance;
|
|
250
84
|
let authParams;
|
|
251
85
|
if (noAuth) {
|
|
252
|
-
authGuidance =
|
|
253
|
-
1. **OpenAPI spec** \u2192 check \`securitySchemes\` / \`securityDefinitions\` for \`type: http\`, \`type: apiKey\`, or \`type: oauth2\`
|
|
254
|
-
2. **Source code** \u2192 look for the auth middleware signals listed in Step ${enrichStepLabel} of the Execution Plan.
|
|
255
|
-
3. **Route definitions** \u2192 check if routes have auth decorators or middleware applied
|
|
256
|
-
4. **Still unknown** \u2192 proceed with \`authHeader: ""\` and note "auth pattern unrecognized" in your recommendation description.
|
|
257
|
-
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.
|
|
258
|
-
**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.`;
|
|
86
|
+
authGuidance = variant("## Auth verification required", { enrichStep: enrichStepLabel });
|
|
259
87
|
authParams = { authHeader: "" };
|
|
260
88
|
}
|
|
261
89
|
else if (isAuthorizationHeader) {
|
|
@@ -266,31 +94,18 @@ If you find auth requirements, pass the appropriate \`authHeader\` and \`authSch
|
|
|
266
94
|
? (getAuthScheme(wsType, explicitScheme) ?? "<scheme e.g. Bearer, Token or empty>")
|
|
267
95
|
: "<scheme e.g. Bearer, Token or empty>";
|
|
268
96
|
authParams = { authHeader: "Authorization", authScheme: resolvedScheme };
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
To skip auth entirely, pass \`authHeader: ""\`.`;
|
|
278
|
-
}
|
|
279
|
-
else {
|
|
280
|
-
authGuidance = `**Auth Scheme:** No \`api.authType\` in workspace config.
|
|
281
|
-
**Where to find the scheme** (check in order):
|
|
282
|
-
1. **OpenAPI spec** \u2192 look at \`securitySchemes\` / \`securityDefinitions\` for \`type: http, scheme: bearer\` or \`type: apiKey\`
|
|
283
|
-
2. **Source code** \u2192 the auth middleware signals listed in Step ${enrichStepLabel} of the Execution Plan
|
|
284
|
-
3. **Fallback** \u2192 use \`"Bearer"\` only if the project clearly uses JWT or OAuth; otherwise pass \`authScheme: ""\`
|
|
285
|
-
Pass the prefix as \`authScheme\` (e.g., \`"Bearer"\`, \`"Token"\`, \`"Basic"\`). If the API uses raw tokens with no prefix, pass \`authScheme: ""\`.
|
|
286
|
-
**Do NOT guess the scheme.**
|
|
287
|
-
To skip auth for unauthenticated endpoints, pass \`authHeader: ""\`.`;
|
|
288
|
-
}
|
|
97
|
+
// One ladder for both cases: only the first line differs, and step 3 states
|
|
98
|
+
// the workspace-type and no-workspace-type fallbacks side by side.
|
|
99
|
+
authGuidance = variant("## Auth scheme", {
|
|
100
|
+
enrichStep: enrichStepLabel,
|
|
101
|
+
authTypeLine: authTypeValue
|
|
102
|
+
? `The workspace \`api.authType\` is \`"${authTypeValue}"\`.`
|
|
103
|
+
: "No `api.authType` in workspace config.",
|
|
104
|
+
});
|
|
289
105
|
}
|
|
290
106
|
else {
|
|
291
107
|
authParams = { authHeader: authHeaderValue };
|
|
292
|
-
authGuidance =
|
|
293
|
-
To skip auth for unauthenticated endpoints, pass \`authHeader: ""\`.`;
|
|
108
|
+
authGuidance = variant("## Auth header, not Authorization", { authHeader: authHeaderValue });
|
|
294
109
|
}
|
|
295
110
|
const hasWorkspaceAuthType = !!authTypeValue && authTypeValue !== "none";
|
|
296
111
|
const authCallParams = serializeAuthCallParams(authParams);
|
|
@@ -298,79 +113,22 @@ To skip auth for unauthenticated endpoints, pass \`authHeader: ""\`.`;
|
|
|
298
113
|
// has authType (workspace handles generation-time auth). Without authType, pass authHeader only.
|
|
299
114
|
// NOTE: scenario generation always uses full authCallParams so auth is embedded in the test file
|
|
300
115
|
// and the executor sends the correct Authorization header at run time.
|
|
301
|
-
const authHeaderOnlyParams = serializeAuthCallParams({ authHeader: authParams.authHeader });
|
|
302
116
|
const integrationAuthNote = hasWorkspaceAuthType
|
|
303
|
-
?
|
|
304
|
-
:
|
|
117
|
+
? variant("## Integration auth, workspace handles it", { authConflictError: AUTH_CONFLICT_ERROR_MSG })
|
|
118
|
+
: variant("## Integration auth, header only", {
|
|
119
|
+
authHeaderOnlyParams: serializeAuthCallParams({ authHeader: authParams.authHeader }),
|
|
120
|
+
});
|
|
305
121
|
const authHeaderLine = noAuth
|
|
306
|
-
?
|
|
307
|
-
:
|
|
308
|
-
return
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
1. Call \`skyramp_batch_scenario_test_generation\` with ALL steps in a single call: \`scenarioName\`, \`destination\`,
|
|
319
|
-
\`baseURL\`, \`${authCallParams}\`, and a \`steps\` array where each element has \`method\`, \`path\`, \`requestBody\` OR \`queryParams\`, \`responseBody\`, \`statusCode\`.
|
|
320
|
-
\`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\`.
|
|
321
|
-
**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.
|
|
322
|
-
**OpenAPI spec is NOT required.** \`apiSchema\` is OPTIONAL — omit it if no spec exists.
|
|
323
|
-
**CRITICAL — Query params vs request body:**
|
|
324
|
-
- For **POST/PUT/PATCH**: use \`requestBody\` with realistic field values from source code schemas.
|
|
325
|
-
- 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.
|
|
326
|
-
- For **GET by ID**: no \`requestBody\` or \`queryParams\` needed — the ID is in the path.
|
|
327
|
-
\`responseBody\` should match the actual API response shape from source code (including all fields
|
|
328
|
-
returned by the controller — e.g., \`id\`, \`ownerId\`, \`createdAt\`, included relations like \`collection\`, \`tags\`).
|
|
329
|
-
Wrap in \`{"response": ...}\` if the API uses an envelope pattern. If omitted, a synthetic response is generated.
|
|
330
|
-
Inspect the source code to determine the correct request AND response body shapes — avoid sending \`{}\`.
|
|
331
|
-
**For PATCH/PUT mutation-recalc scenarios:** The request body should include the child
|
|
332
|
-
collection array (e.g. \`"items": [{"product_id": <chained from prior POST>, "quantity": 2}]\`).
|
|
333
|
-
Never send a PATCH that only modifies metadata (discount, status) without also including the
|
|
334
|
-
items/products collection — such a test will not catch collection-level or total-recalculation bugs.
|
|
335
|
-
For UNIQUE-constrained create fields, set the step's \`uniqueFields\` (gjson paths) rather than
|
|
336
|
-
hardcoding timestamp suffixes — the generator makes them run-unique so re-runs don't 409.
|
|
337
|
-
For every resource-creating step (POST/PUT), also add a matching DELETE step for the created
|
|
338
|
-
resource (path ID chained from the create response) so the scenario cleans up after itself.
|
|
339
|
-
For GET/PUT/DELETE with path IDs, use a placeholder — chaining resolves the real ID.
|
|
340
|
-
2. Produces a \`scenario_<name>.json\` in the same \`outputDir\` as the test files (not \`.skyramp/\`).
|
|
341
|
-
3. Call \`skyramp_integration_test_generation\` with \`scenarioFile\`: ${integrationAuthNote}
|
|
342
|
-
Do NOT pass \`chainingKey\` — defaults to \`response.id\`. After generation, the testbot
|
|
343
|
-
will verify and fix path param chaining in the generated test.
|
|
344
|
-
|
|
345
|
-
**For single-endpoint tests (contract):**
|
|
346
|
-
\`skyramp_{type}_test_generation\` with \`endpointURL\` (full URL incl. base + path), \`method\`,
|
|
347
|
-
\`${authCallParams}\`, and \`requestData\` from source code schemas.
|
|
348
|
-
If an OpenAPI spec exists, ALSO pass \`apiSchema\` — it enables schema-aware validation
|
|
349
|
-
(contract tests verify response structure against the spec).
|
|
350
|
-
Without a spec, \`endpointURL\` alone is sufficient.
|
|
351
|
-
${PATH_PARAM_UUID_GUIDANCE}
|
|
352
|
-
|
|
353
|
-
${CONSUMER_MODE_ENABLED ? `**Contract test mode selection — set based on this service's role at the boundary:**
|
|
354
|
-
- \`providerMode: true\` — this service IS the API; validates the implementation matches the spec.
|
|
355
|
-
Use for new or modified endpoints this codebase owns.
|
|
356
|
-
- \`consumerMode: true\` — this service CALLS another API; validates outbound requests conform to the downstream contract.
|
|
357
|
-
Use when the endpoint's implementation makes HTTP calls to external services (look for fetch/axios/httpx/http.Client/service clients).
|
|
358
|
-
A request-aware mock stands in for the real downstream service — no live dependency needed.
|
|
359
|
-
- **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).` : `**Contract tests — provider-only:**
|
|
360
|
-
Only provider-side contract tests are supported. Pass \`providerMode: true\` for new or modified endpoints this codebase owns.`}
|
|
361
|
-
|
|
362
|
-
**For UI tests:**
|
|
363
|
-
1. \`browser_navigate\` to the target URL (from workspace \`api.baseUrl\`)
|
|
364
|
-
2. \`browser_snapshot\` to see the page (ARIA tree)
|
|
365
|
-
3. Interact using \`browser_click\`, \`browser_type\`, \`browser_fill_form\`, etc.
|
|
366
|
-
4. \`browser_snapshot\` after each interaction that changes the page
|
|
367
|
-
5. \`skyramp_export_zip\` with an **absolute** output path: \`<repositoryPath>/.skyramp/<test_name>_trace.zip\`
|
|
368
|
-
6. \`skyramp_ui_test_generation\` with \`playwrightInput\` = the **absolute** path of the exported zip, and \`outputDir\` = ${SERVICE_REFS.frontendTestDirRef} (e.g. \`frontend/tests\`). Do NOT use the backend service's testDirectory — UI tests must go in the frontend service's test directory.
|
|
369
|
-
|
|
370
|
-
Tips: For custom dropdowns (Radix, MUI): click combobox → snapshot → click option (NOT \`browser_select_option\`).
|
|
371
|
-
|
|
372
|
-
**For E2E tests (mixed PR — both backend and frontend changed):**
|
|
373
|
-
Only generate when pre-existing backend trace \`.json\` AND Playwright \`.zip\` both exist in the repo.
|
|
374
|
-
Use them directly with \`skyramp_e2e_test_generation\`.
|
|
375
|
-
If traces are missing, skip E2E and add to \`additionalRecommendations\` with instructions to record them first.`;
|
|
122
|
+
? variant("## Auth line, none configured", {})
|
|
123
|
+
: variant("## Auth line, configured", { authCallParams });
|
|
124
|
+
return fillPlaceholders(readPromptAsset("generate-tests/tool-workflows.md").trim(), {
|
|
125
|
+
authHeaderLine,
|
|
126
|
+
authGuidance,
|
|
127
|
+
authCallParams,
|
|
128
|
+
integrationAuthNote,
|
|
129
|
+
pathParamUuidGuidance: buildPathParamGuidance(),
|
|
130
|
+
frontendTestDir: SERVICE_REFS.frontendTestDirRef,
|
|
131
|
+
enrichStep: enrichStepLabel,
|
|
132
|
+
contractModeSelection: variant(CONSUMER_MODE_ENABLED ? "## Contract modes, consumer enabled" : "## Contract modes, provider only", {}),
|
|
133
|
+
});
|
|
376
134
|
}
|
|
@@ -1,53 +1,25 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Shared
|
|
3
|
-
*
|
|
2
|
+
* Shared prompt primitives, kept out of the prompt modules that use them to
|
|
3
|
+
* avoid circular imports.
|
|
4
4
|
*/
|
|
5
|
-
import { DraftedScenario } from "../../types/RepositoryAnalysis.js";
|
|
6
5
|
/**
|
|
7
|
-
*
|
|
8
|
-
*
|
|
9
|
-
*
|
|
10
|
-
* They used to build the same string in two places from two different inputs —
|
|
11
|
-
* a typed step list on one side, regex-scraped prose on the other — so a fix to
|
|
12
|
-
* one side left the other producing keys that could never match (SKYR-4214).
|
|
13
|
-
*/
|
|
14
|
-
export declare function coverageKey(input: {
|
|
15
|
-
method: string;
|
|
16
|
-
path: string;
|
|
17
|
-
testType: string;
|
|
18
|
-
}): string;
|
|
19
|
-
/**
|
|
20
|
-
* Method-aware coverage keys for external test dedup — one per recorded subject
|
|
21
|
-
* endpoint. Method-aware so that an external test covering "GET /orders" does
|
|
22
|
-
* not block a test for "PUT /orders", a different operation on the same
|
|
23
|
-
* resource.
|
|
6
|
+
* Labels for a hand-written ordered list, taken from declaration order. Insert a
|
|
7
|
+
* key and every later label moves with it — and so does every reference built
|
|
8
|
+
* from the constant. A number counts up; a single letter walks the alphabet.
|
|
24
9
|
*
|
|
25
|
-
*
|
|
26
|
-
*
|
|
27
|
-
* other endpoints. An empty list must never remove anything.
|
|
28
|
-
*/
|
|
29
|
-
export declare function externalDedupKeys(scenario: DraftedScenario): string[];
|
|
30
|
-
/**
|
|
31
|
-
* Resource+type keys (no method) for the GENERATE/ADDITIONAL overlap filter —
|
|
32
|
-
* one per recorded subject endpoint. Same rule as `externalDedupKeys`: remove
|
|
33
|
-
* only on ALL keys, never on an empty list.
|
|
34
|
-
*/
|
|
35
|
-
export declare function scenarioCoverageKeys(scenario: DraftedScenario): string[];
|
|
36
|
-
export declare function isAttackSurfaceSecurityBoundary(scenario: DraftedScenario): boolean;
|
|
37
|
-
export declare function isOrdinaryDirectAuthBoundary(scenario: DraftedScenario): boolean;
|
|
38
|
-
/**
|
|
39
|
-
* Build a set of coverage keys from external (non-Skyramp) tests.
|
|
40
|
-
* Parses `testLocations` entries tagged with `[external]` to extract the
|
|
41
|
-
* method-aware `METHOD::resource::testType` keys they cover.
|
|
10
|
+
* `PromptPlan` numbers the steps it also RENDERS. Use this for a list whose
|
|
11
|
+
* text is written by hand, where a plan's step headers would change the output.
|
|
42
12
|
*/
|
|
43
|
-
export declare function
|
|
44
|
-
export declare const
|
|
45
|
-
export declare const
|
|
46
|
-
export declare const
|
|
47
|
-
|
|
48
|
-
export declare const
|
|
49
|
-
|
|
50
|
-
export declare const
|
|
51
|
-
|
|
13
|
+
export declare function orderedLabels<K extends string>(keys: readonly K[], start?: number | string): Record<K, string>;
|
|
14
|
+
export declare const TASK_ANALYZE_MAINTAIN: string;
|
|
15
|
+
export declare const TASK_GENERATE: string;
|
|
16
|
+
export declare const TASK_SUBMIT: string;
|
|
17
|
+
/** Top-level numbered steps of Task 1 ("Analyze & Maintain"). */
|
|
18
|
+
export declare const TESTBOT_TASK1_STEP_LABELS: Record<"ANALYZE" | "MAINTAIN" | "CODE_REVIEW" | "UI_GROUNDING", string>;
|
|
19
|
+
/** Lettered sub-steps of Task 1's "Maintain existing tests" step. */
|
|
20
|
+
export declare const TESTBOT_TASK1_MAINTAIN_LABELS: Record<"CONFIRM_EXTERNAL" | "TEST_HEALTH" | "UPDATE_INSTRUCTIONS" | "BASELINE" | "APPLY_ACTIONS" | "VERIFY_EXTERNAL", string>;
|
|
21
|
+
/** Lettered bullets of the multi-repo block inside Task 1's analyze step. */
|
|
22
|
+
export declare const TESTBOT_TASK1_MULTIREPO_LABELS: Record<"REGISTER_SERVICES" | "ANALYZE_REPO" | "ON_FAILURE", string>;
|
|
52
23
|
export declare const taskRef: (taskId: string) => string;
|
|
53
|
-
|
|
24
|
+
/** A lettered sub-step, spelled the way the prompt body spells it: `step 2(a)`. */
|
|
25
|
+
export declare const stepSubRef: (stepId: string, subId: string) => string;
|