@skyramp/mcp 0.3.4 → 0.3.6-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/playwright/registerPlaywrightTools.js +92 -30
- package/build/playwright/traceRecordingPrompt.d.ts +6 -0
- package/build/playwright/traceRecordingPrompt.js +6 -2
- package/build/prompts/code-reuse.d.ts +1 -2
- package/build/prompts/code-reuse.js +182 -77
- package/build/prompts/modularization/integration-test-modularization.d.ts +2 -0
- package/build/prompts/modularization/integration-test-modularization.js +83 -41
- package/build/prompts/modularization/render.d.ts +18 -0
- package/build/prompts/modularization/render.js +12 -0
- package/build/prompts/modularization/ui-test-modularization.d.ts +3 -1
- package/build/prompts/modularization/ui-test-modularization.js +89 -47
- package/build/prompts/pom-aware-code-reuse.js +3 -1
- package/build/prompts/shared-helper-policy.d.ts +57 -0
- package/build/prompts/shared-helper-policy.js +135 -0
- package/build/prompts/test-recommendation/diffExecutionPlan.js +62 -56
- package/build/prompts/test-recommendation/fullRepoCatalog.js +19 -8
- package/build/prompts/test-recommendation/recommendationShared.d.ts +28 -6
- package/build/prompts/test-recommendation/recommendationShared.js +90 -16
- package/build/prompts/test-recommendation/registerRecommendTestsPrompt.js +22 -0
- package/build/prompts/test-recommendation/test-recommendation-prompt.d.ts +2 -2
- package/build/prompts/test-recommendation/test-recommendation-prompt.js +3 -3
- package/build/prompts/testbot/testbot-prompts.js +88 -33
- package/build/recommendation/budgeters/shared.js +105 -27
- package/build/recommendation/discriminators.js +13 -2
- package/build/recommendation/planRanker.d.ts +6 -6
- package/build/recommendation/planRanker.js +6 -61
- package/build/services/AnalyticsService.d.ts +7 -0
- package/build/services/AnalyticsService.js +7 -1
- package/build/services/ModularizationService.js +1 -3
- package/build/services/TestDiscoveryService.d.ts +0 -2
- package/build/services/TestDiscoveryService.js +2 -37
- package/build/services/TestGenerationService.d.ts +16 -0
- package/build/services/TestGenerationService.js +86 -10
- package/build/services/containerEnv.js +13 -12
- package/build/tools/code-refactor/codeReuseTool.js +279 -93
- package/build/tools/code-refactor/enhance-state.d.ts +49 -0
- package/build/tools/code-refactor/enhance-state.js +109 -0
- package/build/tools/code-refactor/enhanceAssertionsTool.js +34 -1
- package/build/tools/code-refactor/modularizationTool.js +9 -2
- package/build/tools/code-refactor/reuse-outcome.d.ts +23 -1
- package/build/tools/code-refactor/reuse-outcome.js +14 -4
- package/build/tools/code-refactor/reuse-state.d.ts +127 -5
- package/build/tools/code-refactor/reuse-state.js +628 -16
- package/build/tools/code-refactor/utils-verify-gates.d.ts +26 -0
- package/build/tools/code-refactor/utils-verify-gates.js +100 -0
- package/build/tools/code-refactor/verify-gates.d.ts +2 -1
- package/build/tools/code-refactor/verify-gates.js +90 -25
- package/build/tools/executeSkyrampTestTool.d.ts +19 -0
- package/build/tools/executeSkyrampTestTool.js +158 -8
- package/build/tools/generate-tests/generateBatchScenarioRestTool.js +2 -2
- package/build/tools/generate-tests/generateE2ERestTool.js +16 -0
- package/build/tools/generate-tests/generateUIRestTool.d.ts +1 -0
- package/build/tools/generate-tests/generateUIRestTool.js +22 -0
- package/build/tools/generate-tests/scenarioLint.d.ts +2 -0
- package/build/tools/generate-tests/scenarioLint.js +127 -19
- package/build/tools/generate-tests/trace-reuse-guard.d.ts +20 -0
- package/build/tools/generate-tests/trace-reuse-guard.js +93 -0
- package/build/tools/submitReportTool.d.ts +38 -38
- package/build/tools/submitReportTool.js +487 -104
- package/build/tools/test-management/analyzeChangesTool.d.ts +24 -1
- package/build/tools/test-management/analyzeChangesTool.js +75 -12
- package/build/tools/test-management/analyzeTestHealthTool.js +7 -7
- package/build/tools/test-management/registerTestPlanTool.d.ts +203 -0
- package/build/tools/test-management/registerTestPlanTool.js +149 -23
- package/build/types/Recommendation.d.ts +34 -5
- package/build/types/RepositoryAnalysis.d.ts +133 -114
- package/build/types/RepositoryAnalysis.js +1 -1
- package/build/types/ReuseOutcome.d.ts +102 -6
- package/build/types/ReuseOutcome.js +16 -2
- package/build/types/TestRecommendation.js +21 -3
- package/build/types/TestTypes.js +14 -8
- package/build/types/TestbotReport.d.ts +25 -3
- package/build/types/index.d.ts +2 -2
- package/build/types/index.js +1 -1
- package/build/utils/AnalysisStateManager.d.ts +69 -1
- package/build/utils/AnalysisStateManager.js +69 -5
- package/build/utils/branchDiff.d.ts +10 -0
- package/build/utils/branchDiff.js +28 -0
- package/build/utils/changedRoutes.d.ts +29 -0
- package/build/utils/changedRoutes.js +87 -0
- package/build/utils/featureFlags.d.ts +21 -0
- package/build/utils/featureFlags.js +23 -0
- package/build/utils/frontendIntegration.js +34 -4
- package/build/utils/importerHop.d.ts +2 -8
- package/build/utils/importerHop.js +15 -53
- package/build/utils/pathMatching.d.ts +38 -0
- package/build/utils/pathMatching.js +71 -0
- package/build/utils/pathSignatures.d.ts +22 -0
- package/build/utils/pathSignatures.js +57 -0
- package/build/utils/planMatchKeys.d.ts +16 -3
- package/build/utils/planMatchKeys.js +26 -10
- package/build/utils/pluralization.d.ts +10 -0
- package/build/utils/pluralization.js +18 -0
- package/build/utils/pom-catalog-parse.d.ts +52 -0
- package/build/utils/pom-catalog-parse.js +141 -0
- package/build/utils/pom-scope/selector-extractor.d.ts +12 -0
- package/build/utils/pom-scope/selector-extractor.js +34 -8
- package/build/utils/pom-verify/verify.d.ts +6 -5
- package/build/utils/pom-verify/verify.js +8 -6
- package/build/utils/reportLanguage.d.ts +43 -0
- package/build/utils/reportLanguage.js +125 -0
- package/build/utils/reportVerification.d.ts +74 -4
- package/build/utils/reportVerification.js +259 -3
- package/build/utils/reuseRouting.d.ts +3 -0
- package/build/utils/reuseRouting.js +50 -0
- package/build/utils/routeParsers.d.ts +2 -0
- package/build/utils/routeParsers.js +65 -8
- package/build/utils/scenarioDrafting.d.ts +1 -1
- package/build/utils/scenarioDrafting.js +57 -45
- package/build/utils/subjectEndpoints.d.ts +19 -0
- package/build/utils/subjectEndpoints.js +98 -0
- package/build/utils/testFileClassification.d.ts +11 -0
- package/build/utils/testFileClassification.js +47 -0
- package/build/utils/uiPageEnumerator.d.ts +45 -19
- package/build/utils/uiPageEnumerator.js +95 -51
- package/build/utils/utils-verify/allow.d.ts +16 -0
- package/build/utils/utils-verify/allow.js +68 -0
- package/build/utils/utils-verify/call-sites.d.ts +34 -0
- package/build/utils/utils-verify/call-sites.js +154 -0
- package/build/utils/utils-verify/index.d.ts +7 -0
- package/build/utils/utils-verify/index.js +7 -0
- package/build/utils/utils-verify/language-spec.d.ts +91 -0
- package/build/utils/utils-verify/language-spec.js +210 -0
- package/build/utils/utils-verify/locate.d.ts +39 -0
- package/build/utils/utils-verify/locate.js +199 -0
- package/build/utils/utils-verify/parse.d.ts +34 -0
- package/build/utils/utils-verify/parse.js +177 -0
- package/build/utils/utils-verify/stage.d.ts +24 -0
- package/build/utils/utils-verify/stage.js +107 -0
- package/build/utils/utils-verify/verify.d.ts +63 -0
- package/build/utils/utils-verify/verify.js +168 -0
- package/build/utils/utils.d.ts +3 -1
- package/build/utils/utils.js +3 -1
- package/build/workspace/workspace.d.ts +32 -32
- package/node_modules/playwright/lib/mcp/skyramp/assertTool.js +9 -5
- package/node_modules/playwright/lib/mcp/skyramp/loadTraceTool.js +16 -0
- package/node_modules/playwright/lib/mcp/skyramp/skyRampImport.js +2 -0
- package/node_modules/playwright/lib/mcp/skyramp/traceRecordingBackend.js +115 -14
- package/node_modules/playwright/lib/mcp/test/skyRampExport.js +13 -1
- package/node_modules/playwright/node_modules/playwright-core/.DS_Store +0 -0
- package/node_modules/playwright/node_modules/playwright-core/lib/server/codegen/skyramp/jsonlReader.js +2 -0
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/htmlReport/index.html +27 -253
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/recorder/assets/{codeMirrorModule-DtudTj_v.js → codeMirrorModule-DJMC4zNo.js} +1 -1
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/recorder/assets/index-BW82eAUI.js +196 -0
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/recorder/index.html +1 -1
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/assets/{codeMirrorModule-FNMuBzX1.js → codeMirrorModule-CZfp96qZ.js} +1 -1
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/assets/defaultSettingsView-gpLo02E0.js +809 -0
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/index.Bq1r1URj.js +2 -0
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/index.html +2 -2
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/uiMode.VEfqi1qN.js +5 -0
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/uiMode.html +2 -2
- package/node_modules/playwright/node_modules/playwright-core/package.json +1 -1
- package/node_modules/playwright/node_modules/playwright-core/src/server/codegen/skyramp/jsonlReader.ts +1 -1
- package/node_modules/playwright/package.json +1 -1
- package/package.json +2 -2
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/recorder/assets/index-BpDwp16L.js +0 -422
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/assets/defaultSettingsView-Co9upU5h.js +0 -1035
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/index.DXNIQ_dx.js +0 -2
- package/node_modules/playwright/node_modules/playwright-core/lib/vite/traceViewer/uiMode.CIKB3XSv.js +0 -5
|
@@ -1,5 +1,12 @@
|
|
|
1
1
|
import { CallToolResult } from "@modelcontextprotocol/sdk/types.js";
|
|
2
2
|
export declare class AnalyticsService {
|
|
3
|
+
/**
|
|
4
|
+
* Only the fields named here reach the analytics backend. The tool's own
|
|
5
|
+
* params are NOT forwarded wholesale: they carry the user's prompt, which is
|
|
6
|
+
* free text about a private codebase and has no business leaving the machine.
|
|
7
|
+
* Anything added here is sent verbatim -- PushToolEvent on the Go side does no
|
|
8
|
+
* redaction of its own -- so add a field only when it is safe to publish.
|
|
9
|
+
*/
|
|
3
10
|
static pushTestGenerationToolEvent(toolName: string, result: CallToolResult, params: Record<string, any>): Promise<void>;
|
|
4
11
|
static pushMCPToolEvent(toolName: string, result: CallToolResult | undefined, params: Record<string, any>): Promise<void>;
|
|
5
12
|
/**
|
|
@@ -40,9 +40,15 @@ async function safePushToolEvent(entryPoint, toolName, errorMessage, params) {
|
|
|
40
40
|
}
|
|
41
41
|
}
|
|
42
42
|
export class AnalyticsService {
|
|
43
|
+
/**
|
|
44
|
+
* Only the fields named here reach the analytics backend. The tool's own
|
|
45
|
+
* params are NOT forwarded wholesale: they carry the user's prompt, which is
|
|
46
|
+
* free text about a private codebase and has no business leaving the machine.
|
|
47
|
+
* Anything added here is sent verbatim -- PushToolEvent on the Go side does no
|
|
48
|
+
* redaction of its own -- so add a field only when it is safe to publish.
|
|
49
|
+
*/
|
|
43
50
|
static async pushTestGenerationToolEvent(toolName, result, params) {
|
|
44
51
|
const analyticsResult = {};
|
|
45
|
-
analyticsResult["prompt"] = params.prompt;
|
|
46
52
|
analyticsResult["language"] = params.language;
|
|
47
53
|
this.pushMCPToolEvent(toolName, result, analyticsResult);
|
|
48
54
|
}
|
|
@@ -28,10 +28,8 @@ The test file \`${params.testFile}\` will remain unchanged. No further action is
|
|
|
28
28
|
let prompt = "";
|
|
29
29
|
switch (testType) {
|
|
30
30
|
case TestType.UI:
|
|
31
|
-
prompt = getModularizationPromptForUI(params.testFile);
|
|
32
|
-
break;
|
|
33
31
|
case TestType.E2E:
|
|
34
|
-
prompt = getModularizationPromptForUI(params.testFile);
|
|
32
|
+
prompt = getModularizationPromptForUI(params.testFile, testType, params.language);
|
|
35
33
|
break;
|
|
36
34
|
case TestType.INTEGRATION:
|
|
37
35
|
prompt = getModularizationPromptForIntegration(params.testFile);
|
|
@@ -45,8 +45,6 @@ export declare class TestDiscoveryService {
|
|
|
45
45
|
private readonly SUPPORTED_EXTENSIONS;
|
|
46
46
|
private readonly MAX_CONCURRENT_OPERATIONS;
|
|
47
47
|
private readonly MAX_EXTERNAL_FULL_REPO;
|
|
48
|
-
private readonly TEST_FILE_PATTERNS;
|
|
49
|
-
private readonly TEST_DIR_PATTERNS;
|
|
50
48
|
/**
|
|
51
49
|
* Discover all tests under testDir — both Skyramp-generated and external (user-written).
|
|
52
50
|
* Uses fast-glob for cross-platform file scanning, then classifies discovered files
|
|
@@ -5,6 +5,7 @@ import { TestSource } from "../types/TestAnalysis.js";
|
|
|
5
5
|
import { TestType } from "../types/TestTypes.js";
|
|
6
6
|
import { buildPathSignatures } from "../utils/pathSignatures.js";
|
|
7
7
|
import fg from "fast-glob";
|
|
8
|
+
import { isDiscoveredTestFile } from "../utils/testFileClassification.js";
|
|
8
9
|
export class TestDiscoveryService {
|
|
9
10
|
EXCLUDED_DIRS = [
|
|
10
11
|
"node_modules",
|
|
@@ -34,37 +35,6 @@ export class TestDiscoveryService {
|
|
|
34
35
|
// In PR mode this hard limit is replaced by relevance-based partitioning which
|
|
35
36
|
// naturally bounds the read set to files relevant to the changed endpoints.
|
|
36
37
|
MAX_EXTERNAL_FULL_REPO = 100;
|
|
37
|
-
// Test file naming patterns — match against basename.
|
|
38
|
-
// Includes Skyramp-generated suffixes so that files like orders_smoke.py placed
|
|
39
|
-
// outside a recognized test directory are still discovered.
|
|
40
|
-
TEST_FILE_PATTERNS = [
|
|
41
|
-
/^test_.*\.(py|js|ts|rb|go|php)$/, // test_*.py, test_*.rb, test_*.go
|
|
42
|
-
/.*_test\.(py|ts|js|go|rs)$/, // *_test.py, *_test.go, *_test.rs
|
|
43
|
-
/.*\.test\.(ts|js|tsx|jsx)$/, // *.test.ts, *.test.js, *.test.tsx
|
|
44
|
-
/.*\..*spec\.(ts|js|tsx|jsx|rb)$/, // *.spec.ts, *.e2e-spec.ts, *.unit-spec.ts
|
|
45
|
-
/.*Test\.(java|kt|kts|cs|scala|swift|m)$/, // *Test.java, *Test.kt, *Test.m (ObjC)
|
|
46
|
-
/.*Tests\.(cs|swift|m)$/, // *Tests.cs, *Tests.swift, *Tests.m (ObjC)
|
|
47
|
-
/.*_spec\.rb$/, // *_spec.rb (RSpec)
|
|
48
|
-
/.*\.test\.php$/, // *.test.php
|
|
49
|
-
/.*Test\.php$/, // *Test.php (PHPUnit)
|
|
50
|
-
// Skyramp-generated test suffixes — must be matched even outside test dirs
|
|
51
|
-
/.*_(?:smoke|contract|fuzz|integration|load|e2e|ui)\.(py|ts|js|java|rb|go|cs|kt|kts|scala|swift|php|rs)$/i,
|
|
52
|
-
];
|
|
53
|
-
// Directory patterns that signal test-owned files — works with both / and \ separators.
|
|
54
|
-
// Includes standard test dirs, snapshot dirs, and common helper/fixture dirs used by
|
|
55
|
-
// Playwright, Cypress, and other frameworks for page objects and support code.
|
|
56
|
-
TEST_DIR_PATTERNS = [
|
|
57
|
-
/[\\/]tests?[\\/]/,
|
|
58
|
-
/[\\/]__tests__[\\/]/,
|
|
59
|
-
/[\\/]__snapshots__[\\/]/, // Jest/Vitest snapshot directories
|
|
60
|
-
/[\\/]spec[\\/]/,
|
|
61
|
-
/[\\/]e2e[\\/]/,
|
|
62
|
-
/[\\/]cypress[\\/]/, // Cypress support, fixtures, plugins
|
|
63
|
-
/[\\/]playwright[\\/]/, // Playwright fixtures and helpers
|
|
64
|
-
/[\\/]page-?objects?[\\/]/, // page-objects/, page-object/, pageObjects/
|
|
65
|
-
/[\\/]fixtures[\\/](?!db[\\/]|seed[\\/]|migrations[\\/])/, // test fixture files (not db/seed/migration fixtures)
|
|
66
|
-
/[\\/]cypress[\\/]support[\\/]/, // Cypress support directory (scoped to avoid matching app support/ dirs)
|
|
67
|
-
];
|
|
68
38
|
/**
|
|
69
39
|
* Discover all tests under testDir — both Skyramp-generated and external (user-written).
|
|
70
40
|
* Uses fast-glob for cross-platform file scanning, then classifies discovered files
|
|
@@ -478,12 +448,7 @@ export class TestDiscoveryService {
|
|
|
478
448
|
* or directory placement.
|
|
479
449
|
*/
|
|
480
450
|
isExternalTestFile(filePath) {
|
|
481
|
-
|
|
482
|
-
if (this.TEST_FILE_PATTERNS.some(p => p.test(basename)))
|
|
483
|
-
return true;
|
|
484
|
-
if (this.TEST_DIR_PATTERNS.some(p => p.test(filePath)))
|
|
485
|
-
return true;
|
|
486
|
-
return false;
|
|
451
|
+
return isDiscoveredTestFile(filePath);
|
|
487
452
|
}
|
|
488
453
|
/**
|
|
489
454
|
* Extract metadata from a test file
|
|
@@ -44,6 +44,15 @@ export interface BaseTestParams {
|
|
|
44
44
|
* empty-string edge (SKYR-3899).
|
|
45
45
|
*/
|
|
46
46
|
export declare function deriveEffectiveFramework(language: string | undefined, framework: string | undefined): string;
|
|
47
|
+
/** The files codegen reports it wrote — the block every generation result carries:
|
|
48
|
+
*
|
|
49
|
+
* Successfully generated/updated tests files:
|
|
50
|
+
* \t/abs/path/to/orders_integration_test.py
|
|
51
|
+
*
|
|
52
|
+
* Read from the result rather than inferred from the filesystem, so a leftover from an
|
|
53
|
+
* earlier attempt or a sibling written by another call is never mistaken for this call's
|
|
54
|
+
* output. Empty when the block is absent (nothing to hand off). */
|
|
55
|
+
export declare function generatedFilesFrom(result: string): string[];
|
|
47
56
|
export declare abstract class TestGenerationService {
|
|
48
57
|
protected client: SkyrampClient;
|
|
49
58
|
constructor();
|
|
@@ -51,6 +60,13 @@ export declare abstract class TestGenerationService {
|
|
|
51
60
|
protected validateInputs(params: BaseTestParams): CallToolResult;
|
|
52
61
|
protected abstract buildGenerationOptions(params: BaseTestParams & Record<string, any>): any;
|
|
53
62
|
protected abstract getTestType(): TestType | typeof MOCK_TYPE;
|
|
63
|
+
/**
|
|
64
|
+
* Whether this generation's codeReuse hand-off sequences skyramp_modularization
|
|
65
|
+
* before skyramp_reuse_code (routing: isModularizeFirstTarget). Subclasses that
|
|
66
|
+
* add their own post-generation steps consult this so modularization is
|
|
67
|
+
* instructed exactly once.
|
|
68
|
+
*/
|
|
69
|
+
protected emitsModularizeFirstHandOff(params: BaseTestParams): boolean;
|
|
54
70
|
protected handleApiAnalysis(params: BaseTestParams): Promise<CallToolResult | null>;
|
|
55
71
|
private static readonly STANDARD_HEADERS;
|
|
56
72
|
private static simpleWildcardMatch;
|
|
@@ -3,7 +3,7 @@ import fs from "fs";
|
|
|
3
3
|
import { SkyrampClient } from "@skyramp/skyramp";
|
|
4
4
|
import { analyzeOpenAPIWithGivenEndpoint } from "../utils/analyze-openapi.js";
|
|
5
5
|
import { isAuthorizationHeaderName, KNOWN_AUTH_HEADERS, resolveAuthFromWorkspace, getWorkspaceSkipTLSVerify, getWorkspaceScopedQueryParams, mergeQueryParamsString, } from "../utils/workspaceAuth.js";
|
|
6
|
-
import { extractPathname, resolveQueryParamsForPath, contributesNothing } from "../workspace/queryParamResolution.js";
|
|
6
|
+
import { extractPathname, resolveQueryParamsForPath, contributesNothing, } from "../workspace/queryParamResolution.js";
|
|
7
7
|
import { getPathParameterValidationError, OUTPUT_DIR_FIELD_NAME, PATH_PARAMS_FIELD_NAME, QUERY_PARAMS_FIELD_NAME, FORM_PARAMS_FIELD_NAME, validateParams, validatePath, validateRequestData, } from "../utils/utils.js";
|
|
8
8
|
import { getEntryPoint } from "../utils/telemetry.js";
|
|
9
9
|
import { getLanguageSteps } from "../utils/language-helper.js";
|
|
@@ -12,6 +12,8 @@ import { logger } from "../utils/logger.js";
|
|
|
12
12
|
import { normalizeLanguageParams } from "../utils/normalizeParams.js";
|
|
13
13
|
import { stageGeneratedPaths, resolveOutputDir } from "../utils/gitStaging.js";
|
|
14
14
|
import { getTestsRepoDir } from "../utils/AnalysisStateManager.js";
|
|
15
|
+
import { recordReuseHandOff } from "../tools/code-refactor/reuse-state.js";
|
|
16
|
+
import { isModularizeFirstTarget } from "../utils/reuseRouting.js";
|
|
15
17
|
/**
|
|
16
18
|
* Derive the framework actually used for generation from the (normalized)
|
|
17
19
|
* language + framework params. A blank/whitespace-only framework is treated as
|
|
@@ -35,10 +37,24 @@ export function deriveEffectiveFramework(language, framework) {
|
|
|
35
37
|
* defaultQueryParams value into that path is not what the design intends
|
|
36
38
|
* (SKYR-4050).
|
|
37
39
|
*/
|
|
38
|
-
const SKIP_DEFAULT_QUERY_PARAMS_TEST_TYPES = new Set([
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
40
|
+
const SKIP_DEFAULT_QUERY_PARAMS_TEST_TYPES = new Set([TestType.UI, TestType.E2E]);
|
|
41
|
+
/** The files codegen reports it wrote — the block every generation result carries:
|
|
42
|
+
*
|
|
43
|
+
* Successfully generated/updated tests files:
|
|
44
|
+
* \t/abs/path/to/orders_integration_test.py
|
|
45
|
+
*
|
|
46
|
+
* Read from the result rather than inferred from the filesystem, so a leftover from an
|
|
47
|
+
* earlier attempt or a sibling written by another call is never mistaken for this call's
|
|
48
|
+
* output. Empty when the block is absent (nothing to hand off). */
|
|
49
|
+
export function generatedFilesFrom(result) {
|
|
50
|
+
const m = /Successfully generated\/updated tests? files?:\s*\n((?:[ \t]+\S[^\n]*\n?)+)/i.exec(result);
|
|
51
|
+
if (!m)
|
|
52
|
+
return [];
|
|
53
|
+
return m[1]
|
|
54
|
+
.split("\n")
|
|
55
|
+
.map((l) => l.trim())
|
|
56
|
+
.filter((l) => l.length > 0 && path.isAbsolute(l));
|
|
57
|
+
}
|
|
42
58
|
export class TestGenerationService {
|
|
43
59
|
client;
|
|
44
60
|
constructor() {
|
|
@@ -74,6 +90,9 @@ export class TestGenerationService {
|
|
|
74
90
|
return apiAnalysisResult;
|
|
75
91
|
}
|
|
76
92
|
const result = await this.executeGeneration(generateOptions);
|
|
93
|
+
// The files this call wrote, as codegen reports them — the reuse hand-off is
|
|
94
|
+
// recorded per FILE (SKYR-4220).
|
|
95
|
+
const written = generatedFilesFrom(result);
|
|
77
96
|
const testType = this.getTestType();
|
|
78
97
|
const languageSteps = getLanguageSteps({
|
|
79
98
|
language: params.language || "",
|
|
@@ -83,12 +102,57 @@ export class TestGenerationService {
|
|
|
83
102
|
// Orchestrate code optimization workflow based on flags
|
|
84
103
|
let postGenerationMessage = "";
|
|
85
104
|
if (params.codeReuse) {
|
|
86
|
-
//
|
|
87
|
-
|
|
105
|
+
// Name the framework generation actually used, not the raw parameter:
|
|
106
|
+
// TS/JS derive to playwright when the caller omitted it, and
|
|
107
|
+
// skyramp_reuse_code requires framework to route correctly.
|
|
108
|
+
const effectiveFramework = deriveEffectiveFramework(params.language || "", params.framework);
|
|
109
|
+
const reuseArgs = `\`testFile\` set to the absolute path of the generated test file, \`language: "${params.language}"\`, \`testType: "${testType}"\`${effectiveFramework ? `, and \`framework: "${effectiveFramework}"\`` : ""}`;
|
|
110
|
+
// Modularize-first: fresh codegen carries no helper functions (each
|
|
111
|
+
// endpoint called once, each browser step inline), so modularization is
|
|
112
|
+
// what creates the named helpers that reuse then consolidates into the
|
|
113
|
+
// shared utils file. Emitted here, not in the testbot prompt, so the
|
|
114
|
+
// instruction exists only on runs that actually generated this test type
|
|
115
|
+
// and needs no hand-maintained step numbering.
|
|
116
|
+
if (this.emitsModularizeFirstHandOff(params)) {
|
|
117
|
+
// SKYR-4220: record the hand-off at the site that emits it, under the same
|
|
118
|
+
// condition, so skyramp_execute_test can refuse a test that skipped the pair
|
|
119
|
+
// and the report can mark it — without ever owing it for a test that was not
|
|
120
|
+
// told to run it. Keyed by the files this call wrote: a test generated into
|
|
121
|
+
// the same directory without codeReuse owes nothing.
|
|
122
|
+
await recordReuseHandOff(written, testType, params.language || "", effectiveFramework);
|
|
123
|
+
// Browser tests: the assertion enhancer anchors new assertions to
|
|
124
|
+
// selectors present in the test file, and after modularize → reuse
|
|
125
|
+
// those selectors live in the utils file. So for UI the enhancer runs
|
|
126
|
+
// FIRST, on the raw file; the extraction rules then keep every value
|
|
127
|
+
// assertion in the test body. API enhancers key off response paths,
|
|
128
|
+
// so integration keeps its validated modularize → reuse → enhance order.
|
|
129
|
+
const enhanceFirst = testType === TestType.UI && !!params.enhanceAssertions;
|
|
130
|
+
const steps = [
|
|
131
|
+
...(enhanceFirst
|
|
132
|
+
? [
|
|
133
|
+
`Call \`skyramp_enhance_assertions\` with \`testFile\` set to the absolute path of the generated test file, \`testType: "${testType}"\`, and \`enhanceType: "generation"\`, and apply every instruction returned to that file — BEFORE modularization, while the file's selectors are still inline.`,
|
|
134
|
+
]
|
|
135
|
+
: []),
|
|
136
|
+
`Call \`skyramp_modularization\` with \`testFile\`, \`testType: "${testType}"\`, and \`isTraceBased: true\`, and apply the returned instructions — this extracts the test's steps into named helper functions, which is what makes cross-test reuse possible.`,
|
|
137
|
+
`Immediately after writing the modularized file — as your very NEXT skyramp tool call — call \`skyramp_reuse_code\` with ${reuseArgs}. The modularization call does NOT count as this step: reuse is a separate tool and MUST be invoked even when you expect it to find nothing. Follow the returned steps to completion. Sibling tests offering nothing to reuse is a normal outcome — the returned steps still move THIS test's own helpers into the shared utils file and import them back, so the test file IS expected to change; finish those steps, then continue (do NOT retry).`,
|
|
138
|
+
];
|
|
139
|
+
const ordering = enhanceFirst
|
|
140
|
+
? "three sub-steps, STRICTLY SEQUENTIAL (never in the same tool-call batch)"
|
|
141
|
+
: "two sub-steps, STRICTLY SEQUENTIAL (never in the same tool-call batch), BOTH BEFORE `skyramp_enhance_assertions`";
|
|
142
|
+
postGenerationMessage += `
|
|
143
|
+
Test generated successfully!
|
|
144
|
+
|
|
145
|
+
⏭️**CRITICAL NEXT STEPS — ${ordering}**:
|
|
146
|
+
${steps.map((text, i) => `${String.fromCharCode(97 + i)}. ${text}`).join("\n")}
|
|
147
|
+
`;
|
|
148
|
+
}
|
|
149
|
+
else {
|
|
150
|
+
postGenerationMessage += `
|
|
88
151
|
Test generated successfully!
|
|
89
152
|
|
|
90
|
-
⏭️**CRITICAL NEXT STEP**:
|
|
153
|
+
⏭️**CRITICAL NEXT STEP**: Run code reuse analysis by calling the skyramp_reuse_code tool with ${reuseArgs}.
|
|
91
154
|
`;
|
|
155
|
+
}
|
|
92
156
|
}
|
|
93
157
|
else if (params.modularizeCode) {
|
|
94
158
|
// Check if test type should be modularized
|
|
@@ -210,6 +274,16 @@ The generated test file remains unchanged and ready to use as-is.
|
|
|
210
274
|
? { content: [], isError: false }
|
|
211
275
|
: errList;
|
|
212
276
|
}
|
|
277
|
+
/**
|
|
278
|
+
* Whether this generation's codeReuse hand-off sequences skyramp_modularization
|
|
279
|
+
* before skyramp_reuse_code (routing: isModularizeFirstTarget). Subclasses that
|
|
280
|
+
* add their own post-generation steps consult this so modularization is
|
|
281
|
+
* instructed exactly once.
|
|
282
|
+
*/
|
|
283
|
+
emitsModularizeFirstHandOff(params) {
|
|
284
|
+
return (!!params.codeReuse &&
|
|
285
|
+
isModularizeFirstTarget(this.getTestType(), params.language));
|
|
286
|
+
}
|
|
213
287
|
async handleApiAnalysis(params) {
|
|
214
288
|
if (params.apiSchema && params.endpointURL && params.method === "") {
|
|
215
289
|
try {
|
|
@@ -274,7 +348,9 @@ The generated test file remains unchanged and ready to use as-is.
|
|
|
274
348
|
// KNOWN_AUTH_HEADERS is imported from workspaceAuth.ts — single source of truth
|
|
275
349
|
// shared with trace-parser.ts for redaction. See workspaceAuth.ts for the full list.
|
|
276
350
|
static simpleWildcardMatch(pattern, value) {
|
|
277
|
-
const regex = new RegExp("^" +
|
|
351
|
+
const regex = new RegExp("^" +
|
|
352
|
+
pattern.replace(/[.+^${}()|[\]\\]/g, "\\$&").replace(/\*/g, ".*") +
|
|
353
|
+
"$");
|
|
278
354
|
return regex.test(value);
|
|
279
355
|
}
|
|
280
356
|
static traceMatchesFilters(entry, include, exclude) {
|
|
@@ -421,7 +497,7 @@ The generated test file remains unchanged and ready to use as-is.
|
|
|
421
497
|
// authType handles the Authorization header implicitly — the Go CLI treats
|
|
422
498
|
// --auth-type and --auth-header as mutually exclusive, so clear authHeader
|
|
423
499
|
// when it's the standard Authorization header to avoid the conflict.
|
|
424
|
-
if (isAuthorizationHeaderName(generateOptions.authHeader ||
|
|
500
|
+
if (isAuthorizationHeaderName(generateOptions.authHeader || "")) {
|
|
425
501
|
delete generateOptions.authHeader;
|
|
426
502
|
}
|
|
427
503
|
}
|
|
@@ -106,23 +106,24 @@ export function buildContainerEnv(options, saveStoragePath, hostEnv = process.en
|
|
|
106
106
|
// carrying as literals (SKYR-3862). Without this the container never sees
|
|
107
107
|
// them and every generated login fails its guard.
|
|
108
108
|
//
|
|
109
|
+
// Matched by prefix, like the service URLs above: a multi-credential
|
|
110
|
+
// `uiCredentials` input exports one keyed pair per credential —
|
|
111
|
+
// SKYRAMP_UI_USERNAME_<KEY> / SKYRAMP_UI_PASSWORD_<KEY> — alongside the
|
|
112
|
+
// unkeyed first-credential pair, and codegen binds each generated test to
|
|
113
|
+
// the pair it was recorded with (SKYR-4110). Dropping a keyed pair here
|
|
114
|
+
// would fail that test's guard even though the run provided the credential.
|
|
115
|
+
//
|
|
109
116
|
// Forwarded on presence, not truthiness: the generated guard deliberately
|
|
110
117
|
// distinguishes an unset variable (a misconfiguration, fails fast) from one
|
|
111
118
|
// set to "" (valid on forms that accept a blank password). A truthy check —
|
|
112
119
|
// as used for the URL vars above — would drop the empty case and collapse it
|
|
113
120
|
// into the failure case.
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
// (SKYRAMP_UI_PASSWORD_<KEY>), which needs no new forwarding logic here: the
|
|
121
|
-
// loop above already forwards SKYRAMP_TEST_SERVICE_URL_* by prefix, so the
|
|
122
|
-
// same approach applies. Keep the presence-not-truthiness rule when it lands.
|
|
123
|
-
for (const key of ["SKYRAMP_UI_USERNAME", "SKYRAMP_UI_PASSWORD"]) {
|
|
124
|
-
const val = hostEnv[key];
|
|
125
|
-
if (val !== undefined) {
|
|
121
|
+
for (const [key, val] of Object.entries(hostEnv)) {
|
|
122
|
+
const isCredential = key === "SKYRAMP_UI_USERNAME" ||
|
|
123
|
+
key === "SKYRAMP_UI_PASSWORD" ||
|
|
124
|
+
key.startsWith("SKYRAMP_UI_USERNAME_") ||
|
|
125
|
+
key.startsWith("SKYRAMP_UI_PASSWORD_");
|
|
126
|
+
if (isCredential && val !== undefined) {
|
|
126
127
|
env.push(`${key}=${val}`);
|
|
127
128
|
}
|
|
128
129
|
}
|