@testchimp/cli 0.1.5 → 0.1.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli/program.js +10 -1
- package/dist/core/schemas.d.ts +21 -0
- package/dist/core/schemas.js +11 -0
- package/dist/core/tools.js +45 -8
- package/dist/core/truecoverageScope.d.ts +16 -0
- package/dist/core/truecoverageScope.js +74 -0
- package/package.json +1 -1
package/dist/cli/program.js
CHANGED
|
@@ -46,6 +46,7 @@ export function buildCliProgram() {
|
|
|
46
46
|
.option("--release <s>")
|
|
47
47
|
.option("--environment <s>")
|
|
48
48
|
.option("--branch-name <s>")
|
|
49
|
+
.option("--platform <web|ios|android>")
|
|
49
50
|
.option("--file-paths <csv>", "comma-separated paths under platform tests root")
|
|
50
51
|
.option("--folder-path <path>", "folder under tests root, slash-separated")
|
|
51
52
|
.action(async (opts) => {
|
|
@@ -56,6 +57,8 @@ export function buildCliProgram() {
|
|
|
56
57
|
body.environment = opts.environment;
|
|
57
58
|
if (opts.branchName)
|
|
58
59
|
body.branchName = opts.branchName;
|
|
60
|
+
if (opts.platform)
|
|
61
|
+
body.platform = opts.platform;
|
|
59
62
|
const scope = {};
|
|
60
63
|
if (opts.filePaths)
|
|
61
64
|
scope.filePaths = String(opts.filePaths).split(",").map((s) => s.trim()).filter(Boolean);
|
|
@@ -74,6 +77,8 @@ export function buildCliProgram() {
|
|
|
74
77
|
.option("--release <s>")
|
|
75
78
|
.option("--environment <s>")
|
|
76
79
|
.option("--branch-name <s>")
|
|
80
|
+
.option("--scenario-id <id>")
|
|
81
|
+
.option("--platform <web|ios|android>")
|
|
77
82
|
.option("--file-paths <csv>")
|
|
78
83
|
.option("--folder-path <path>")
|
|
79
84
|
.action(async (opts) => {
|
|
@@ -84,6 +89,10 @@ export function buildCliProgram() {
|
|
|
84
89
|
body.environment = opts.environment;
|
|
85
90
|
if (opts.branchName)
|
|
86
91
|
body.branchName = opts.branchName;
|
|
92
|
+
if (opts.scenarioId)
|
|
93
|
+
body.scenarioId = opts.scenarioId;
|
|
94
|
+
if (opts.platform)
|
|
95
|
+
body.platform = opts.platform;
|
|
87
96
|
const scope = {};
|
|
88
97
|
if (opts.filePaths)
|
|
89
98
|
scope.filePaths = String(opts.filePaths).split(",").map((s) => s.trim()).filter(Boolean);
|
|
@@ -332,7 +341,7 @@ export function buildCliProgram() {
|
|
|
332
341
|
const out = await runTool("list-rum-environments", merged, { postMcp });
|
|
333
342
|
console.log(out);
|
|
334
343
|
});
|
|
335
|
-
const truecoverageHelp = "
|
|
344
|
+
const truecoverageHelp = "Use --json-input with full request JSON (proto-shaped; set platform inside each ExecutionScope).";
|
|
336
345
|
program
|
|
337
346
|
.command("get-truecoverage-events")
|
|
338
347
|
.description(TOOL_DEFINITIONS.find((t) => t.kebab === "get-truecoverage-events").description + " " + truecoverageHelp)
|
package/dist/core/schemas.d.ts
CHANGED
|
@@ -3,6 +3,10 @@ export declare const scopeSchema: z.ZodOptional<z.ZodObject<{
|
|
|
3
3
|
filePaths: z.ZodOptional<z.ZodArray<z.ZodString>>;
|
|
4
4
|
folderPath: z.ZodOptional<z.ZodUnion<readonly [z.ZodArray<z.ZodString>, z.ZodString]>>;
|
|
5
5
|
}, z.core.$strip>>;
|
|
6
|
+
export declare const executionJobDimensionFilterSchema: z.ZodObject<{
|
|
7
|
+
dimension: z.ZodString;
|
|
8
|
+
values: z.ZodArray<z.ZodString>;
|
|
9
|
+
}, z.core.$strip>;
|
|
6
10
|
export declare const listCoverageInput: z.ZodObject<{
|
|
7
11
|
release: z.ZodOptional<z.ZodString>;
|
|
8
12
|
environment: z.ZodOptional<z.ZodString>;
|
|
@@ -13,6 +17,11 @@ export declare const listCoverageInput: z.ZodObject<{
|
|
|
13
17
|
includeNonCoveredUserStories: z.ZodOptional<z.ZodBoolean>;
|
|
14
18
|
includeNonCoveredTestScenarios: z.ZodOptional<z.ZodBoolean>;
|
|
15
19
|
branchName: z.ZodOptional<z.ZodString>;
|
|
20
|
+
platform: z.ZodOptional<z.ZodEnum<{
|
|
21
|
+
web: "web";
|
|
22
|
+
ios: "ios";
|
|
23
|
+
android: "android";
|
|
24
|
+
}>>;
|
|
16
25
|
}, z.core.$strip>;
|
|
17
26
|
export declare const listExecutionInput: z.ZodObject<{
|
|
18
27
|
release: z.ZodOptional<z.ZodString>;
|
|
@@ -22,6 +31,18 @@ export declare const listExecutionInput: z.ZodObject<{
|
|
|
22
31
|
folderPath: z.ZodOptional<z.ZodUnion<readonly [z.ZodArray<z.ZodString>, z.ZodString]>>;
|
|
23
32
|
}, z.core.$strip>>;
|
|
24
33
|
branchName: z.ZodOptional<z.ZodString>;
|
|
34
|
+
scenarioId: z.ZodOptional<z.ZodString>;
|
|
35
|
+
platform: z.ZodOptional<z.ZodEnum<{
|
|
36
|
+
web: "web";
|
|
37
|
+
ios: "ios";
|
|
38
|
+
android: "android";
|
|
39
|
+
}>>;
|
|
40
|
+
dimensionFilters: z.ZodOptional<z.ZodArray<z.ZodObject<{
|
|
41
|
+
dimension: z.ZodString;
|
|
42
|
+
values: z.ZodArray<z.ZodString>;
|
|
43
|
+
}, z.core.$strip>>>;
|
|
44
|
+
limit: z.ZodOptional<z.ZodNumber>;
|
|
45
|
+
offset: z.ZodOptional<z.ZodNumber>;
|
|
25
46
|
}, z.core.$strip>;
|
|
26
47
|
export declare const fetchExecutionReportInput: z.ZodObject<{
|
|
27
48
|
batchInvocationId: z.ZodOptional<z.ZodString>;
|
package/dist/core/schemas.js
CHANGED
|
@@ -5,6 +5,11 @@ export const scopeSchema = z
|
|
|
5
5
|
folderPath: z.union([z.array(z.string()), z.string()]).optional(),
|
|
6
6
|
})
|
|
7
7
|
.optional();
|
|
8
|
+
const executionPlatformSchema = z.enum(["web", "ios", "android"]);
|
|
9
|
+
export const executionJobDimensionFilterSchema = z.object({
|
|
10
|
+
dimension: z.string().min(1),
|
|
11
|
+
values: z.array(z.string()).min(1),
|
|
12
|
+
});
|
|
8
13
|
export const listCoverageInput = z.object({
|
|
9
14
|
release: z.string().optional(),
|
|
10
15
|
environment: z.string().optional(),
|
|
@@ -12,12 +17,18 @@ export const listCoverageInput = z.object({
|
|
|
12
17
|
includeNonCoveredUserStories: z.boolean().optional(),
|
|
13
18
|
includeNonCoveredTestScenarios: z.boolean().optional(),
|
|
14
19
|
branchName: z.string().optional(),
|
|
20
|
+
platform: executionPlatformSchema.optional(),
|
|
15
21
|
});
|
|
16
22
|
export const listExecutionInput = z.object({
|
|
17
23
|
release: z.string().optional(),
|
|
18
24
|
environment: z.string().optional(),
|
|
19
25
|
scope: scopeSchema,
|
|
20
26
|
branchName: z.string().optional(),
|
|
27
|
+
scenarioId: z.string().optional(),
|
|
28
|
+
platform: executionPlatformSchema.optional(),
|
|
29
|
+
dimensionFilters: z.array(executionJobDimensionFilterSchema).optional(),
|
|
30
|
+
limit: z.number().int().positive().max(500).optional(),
|
|
31
|
+
offset: z.number().int().nonnegative().optional(),
|
|
21
32
|
});
|
|
22
33
|
export const fetchExecutionReportInput = z
|
|
23
34
|
.object({
|
package/dist/core/tools.js
CHANGED
|
@@ -1,6 +1,16 @@
|
|
|
1
1
|
import { normalizeScope } from "./normalize.js";
|
|
2
2
|
import { runProvisionEphemeralEnvironmentAndWait } from "./ephemeralWait.js";
|
|
3
3
|
import * as S from "./schemas.js";
|
|
4
|
+
function platformToProtoEnum(platform) {
|
|
5
|
+
switch (platform) {
|
|
6
|
+
case "ios":
|
|
7
|
+
return "IOS_EXECUTION_PLATFORM";
|
|
8
|
+
case "android":
|
|
9
|
+
return "ANDROID_EXECUTION_PLATFORM";
|
|
10
|
+
default:
|
|
11
|
+
return "WEB_EXECUTION_PLATFORM";
|
|
12
|
+
}
|
|
13
|
+
}
|
|
4
14
|
function listCoverageBody(args) {
|
|
5
15
|
const body = {};
|
|
6
16
|
if (args.release != null)
|
|
@@ -16,6 +26,8 @@ function listCoverageBody(args) {
|
|
|
16
26
|
}
|
|
17
27
|
if (args.branchName != null && args.branchName.trim() !== "")
|
|
18
28
|
body.branchName = args.branchName.trim();
|
|
29
|
+
if (args.platform != null)
|
|
30
|
+
body.platform = platformToProtoEnum(args.platform);
|
|
19
31
|
return body;
|
|
20
32
|
}
|
|
21
33
|
function listExecutionBody(args) {
|
|
@@ -28,6 +40,24 @@ function listExecutionBody(args) {
|
|
|
28
40
|
body.scope = normalizeScope(args.scope);
|
|
29
41
|
if (args.branchName != null && args.branchName.trim() !== "")
|
|
30
42
|
body.branchName = args.branchName.trim();
|
|
43
|
+
if (args.scenarioId != null && args.scenarioId.trim() !== "")
|
|
44
|
+
body.scenarioId = args.scenarioId.trim();
|
|
45
|
+
const dimensionFilters = [...(args.dimensionFilters ?? [])];
|
|
46
|
+
if (args.platform != null) {
|
|
47
|
+
const hasPlatformFilter = dimensionFilters.some((f) => f.dimension === "PLATFORM_EXECUTION_JOB_FILTER_DIMENSION");
|
|
48
|
+
if (!hasPlatformFilter) {
|
|
49
|
+
dimensionFilters.push({
|
|
50
|
+
dimension: "PLATFORM_EXECUTION_JOB_FILTER_DIMENSION",
|
|
51
|
+
values: [args.platform.toUpperCase()],
|
|
52
|
+
});
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
if (dimensionFilters.length > 0)
|
|
56
|
+
body.dimensionFilters = dimensionFilters;
|
|
57
|
+
if (args.limit != null)
|
|
58
|
+
body.limit = args.limit;
|
|
59
|
+
if (args.offset != null)
|
|
60
|
+
body.offset = args.offset;
|
|
31
61
|
return body;
|
|
32
62
|
}
|
|
33
63
|
export const TOOL_DEFINITIONS = [
|
|
@@ -36,7 +66,7 @@ export const TOOL_DEFINITIONS = [
|
|
|
36
66
|
description: "Fetch requirement (scenario) coverage under an optional platform-rooted folder scope (tests/... or plans/...). " +
|
|
37
67
|
"Use scope.filePaths or scope.folderPath (platform tests/plans roots). Omit branchName for cross-branch coverage " +
|
|
38
68
|
"(aggregates branch copies; execution jobs deduped by stable hash of tests-root-relative path + test name). " +
|
|
39
|
-
"Pass branchName only when results must be limited to one Git branch.",
|
|
69
|
+
"Pass branchName only when results must be limited to one Git branch. Optional platform (web|ios|android) filters rollup.",
|
|
40
70
|
inputSchema: S.listCoverageInput,
|
|
41
71
|
execute: async (args, { postMcp }) => {
|
|
42
72
|
const json = await postMcp("/api/mcp/list_requirement_coverage", listCoverageBody(args));
|
|
@@ -45,8 +75,8 @@ export const TOOL_DEFINITIONS = [
|
|
|
45
75
|
},
|
|
46
76
|
{
|
|
47
77
|
kebab: "get-execution-history",
|
|
48
|
-
description: "Fetch SmartTest execution history for an optional platform-rooted folder scope. " +
|
|
49
|
-
"Use branchName and scope.filePaths as for coverage.",
|
|
78
|
+
description: "Fetch SmartTest execution history for an optional platform-rooted folder scope, or for a scenario when scenarioId is set. " +
|
|
79
|
+
"Use branchName and scope.filePaths as for coverage. Optional platform (web|ios|android) and dimensionFilters narrow results.",
|
|
50
80
|
inputSchema: S.listExecutionInput,
|
|
51
81
|
execute: async (args, { postMcp }) => {
|
|
52
82
|
const json = await postMcp("/api/mcp/list_execution_history", listExecutionBody(args));
|
|
@@ -243,31 +273,38 @@ export const TOOL_DEFINITIONS = [
|
|
|
243
273
|
},
|
|
244
274
|
{
|
|
245
275
|
kebab: "get-truecoverage-events",
|
|
246
|
-
description: "TrueCoverage event funnel summaries (ListEventsRequest JSON: baseExecutionScope, comparisonExecutionScope)."
|
|
276
|
+
description: "TrueCoverage event funnel summaries (ListEventsRequest JSON: baseExecutionScope, comparisonExecutionScope). " +
|
|
277
|
+
"Optional ExecutionScope.platform: WEB_EXECUTION_PLATFORM | IOS_EXECUTION_PLATFORM | ANDROID_EXECUTION_PLATFORM " +
|
|
278
|
+
"(filters RUM rows stamped via testchimp-rum-platform header: web=1, ios=2, android=3). " +
|
|
279
|
+
"Use automationEmitsOnly on comparisonExecutionScope for test-tagged emits only.",
|
|
247
280
|
inputSchema: S.truecoverageJsonInput,
|
|
248
281
|
execute: async (args, { postMcp }) => postMcp("/api/mcp/truecoverage_list_events", args ?? {}),
|
|
249
282
|
},
|
|
250
283
|
{
|
|
251
284
|
kebab: "get-truecoverage-event-details",
|
|
252
|
-
description: "TrueCoverage drill-down for one event title (GetEventDetailsRequest JSON)."
|
|
285
|
+
description: "TrueCoverage drill-down for one event title (GetEventDetailsRequest JSON). " +
|
|
286
|
+
"Optional platform on baseExecutionScope / comparisonExecutionScope (WEB_EXECUTION_PLATFORM, IOS_EXECUTION_PLATFORM, ANDROID_EXECUTION_PLATFORM).",
|
|
253
287
|
inputSchema: S.truecoverageJsonInput,
|
|
254
288
|
execute: async (args, { postMcp }) => postMcp("/api/mcp/truecoverage_event_details", args ?? {}),
|
|
255
289
|
},
|
|
256
290
|
{
|
|
257
291
|
kebab: "get-truecoverage-child-event-tree",
|
|
258
|
-
description: "TrueCoverage next-event tree for an event (ListChildEventTreeRequest JSON)."
|
|
292
|
+
description: "TrueCoverage next-event tree for an event (ListChildEventTreeRequest JSON). " +
|
|
293
|
+
"Optional platform on baseScope / coverageScope (inside each ExecutionScope).",
|
|
259
294
|
inputSchema: S.truecoverageJsonInput,
|
|
260
295
|
execute: async (args, { postMcp }) => postMcp("/api/mcp/truecoverage_list_child_event_tree", args ?? {}),
|
|
261
296
|
},
|
|
262
297
|
{
|
|
263
298
|
kebab: "get-truecoverage-event-transition",
|
|
264
|
-
description: "TrueCoverage detailed transition summary between events (GetDetailedEventTransitionSummaryRequest JSON)."
|
|
299
|
+
description: "TrueCoverage detailed transition summary between events (GetDetailedEventTransitionSummaryRequest JSON). " +
|
|
300
|
+
"Optional platform on baseScope / coverageScope (inside each ExecutionScope).",
|
|
265
301
|
inputSchema: S.truecoverageJsonInput,
|
|
266
302
|
execute: async (args, { postMcp }) => postMcp("/api/mcp/truecoverage_detailed_event_transition", args ?? {}),
|
|
267
303
|
},
|
|
268
304
|
{
|
|
269
305
|
kebab: "get-truecoverage-event-time-series",
|
|
270
|
-
description: "TrueCoverage time series for sessions or metrics (EventTimeSeriesRequest JSON)."
|
|
306
|
+
description: "TrueCoverage time series for sessions or metrics (EventTimeSeriesRequest JSON). " +
|
|
307
|
+
"Optional platform on baseExecutionScope.",
|
|
271
308
|
inputSchema: S.truecoverageJsonInput,
|
|
272
309
|
execute: async (args, { postMcp }) => postMcp("/api/mcp/truecoverage_event_time_series", args ?? {}),
|
|
273
310
|
},
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** Maps CLI/MCP shorthand to {@code com.aware.common.ExecutionPlatform} JSON enum names. */
|
|
2
|
+
export declare function platformToProtoEnum(platform: "web" | "ios" | "android"): string;
|
|
3
|
+
export type TruecoveragePlatformCli = "web" | "ios" | "android";
|
|
4
|
+
export interface TruecoveragePlatformOpts {
|
|
5
|
+
base?: TruecoveragePlatformCli;
|
|
6
|
+
/** Secondary / coverage-aligned scope (`comparisonExecutionScope` or `coverageScope` per endpoint). */
|
|
7
|
+
comparison?: TruecoveragePlatformCli;
|
|
8
|
+
}
|
|
9
|
+
/** MCP/CLI top-level shortcuts (`basePlatform`, …) stripped before POST. */
|
|
10
|
+
export declare function parseTruecoveragePlatformArgs(args: unknown): TruecoveragePlatformOpts | undefined;
|
|
11
|
+
export declare function stripTruecoveragePlatformShortcuts(body: Record<string, unknown>): Record<string, unknown>;
|
|
12
|
+
/**
|
|
13
|
+
* Apply CLI/MCP platform shortcuts onto nested execution scopes (scope.platform in JSON wins).
|
|
14
|
+
*/
|
|
15
|
+
export declare function applyTruecoveragePlatforms(body: Record<string, unknown>, opts?: TruecoveragePlatformOpts): Record<string, unknown>;
|
|
16
|
+
export declare function prepareTruecoverageRequestBody(args: unknown): Record<string, unknown>;
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/** Maps CLI/MCP shorthand to {@code com.aware.common.ExecutionPlatform} JSON enum names. */
|
|
2
|
+
export function platformToProtoEnum(platform) {
|
|
3
|
+
switch (platform) {
|
|
4
|
+
case "ios":
|
|
5
|
+
return "IOS_EXECUTION_PLATFORM";
|
|
6
|
+
case "android":
|
|
7
|
+
return "ANDROID_EXECUTION_PLATFORM";
|
|
8
|
+
default:
|
|
9
|
+
return "WEB_EXECUTION_PLATFORM";
|
|
10
|
+
}
|
|
11
|
+
}
|
|
12
|
+
function setScopePlatform(scope, platform) {
|
|
13
|
+
if (!scope)
|
|
14
|
+
return;
|
|
15
|
+
scope.platform = platformToProtoEnum(platform);
|
|
16
|
+
}
|
|
17
|
+
function pickPlatformCli(v) {
|
|
18
|
+
if (v === "web" || v === "ios" || v === "android")
|
|
19
|
+
return v;
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
/** MCP/CLI top-level shortcuts (`basePlatform`, …) stripped before POST. */
|
|
23
|
+
export function parseTruecoveragePlatformArgs(args) {
|
|
24
|
+
if (args == null || typeof args !== "object")
|
|
25
|
+
return undefined;
|
|
26
|
+
const a = args;
|
|
27
|
+
const base = pickPlatformCli(a.basePlatform);
|
|
28
|
+
const comparison = pickPlatformCli(a.comparisonPlatform) ?? pickPlatformCli(a.coveragePlatform);
|
|
29
|
+
if (base == null && comparison == null)
|
|
30
|
+
return undefined;
|
|
31
|
+
return { base, comparison };
|
|
32
|
+
}
|
|
33
|
+
export function stripTruecoveragePlatformShortcuts(body) {
|
|
34
|
+
const { basePlatform: _b, comparisonPlatform: _c, coveragePlatform: _v, ...rest } = body;
|
|
35
|
+
return rest;
|
|
36
|
+
}
|
|
37
|
+
function mergeScopePlatform(scope, platform) {
|
|
38
|
+
if (scope == null || scope.platform != null)
|
|
39
|
+
return scope;
|
|
40
|
+
const next = { ...scope };
|
|
41
|
+
setScopePlatform(next, platform);
|
|
42
|
+
return next;
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Apply CLI/MCP platform shortcuts onto nested execution scopes (scope.platform in JSON wins).
|
|
46
|
+
*/
|
|
47
|
+
export function applyTruecoveragePlatforms(body, opts) {
|
|
48
|
+
if (!opts)
|
|
49
|
+
return body;
|
|
50
|
+
const out = { ...body };
|
|
51
|
+
if (opts.base != null) {
|
|
52
|
+
const nextBase = mergeScopePlatform(out.baseExecutionScope, opts.base);
|
|
53
|
+
if (nextBase != null)
|
|
54
|
+
out.baseExecutionScope = nextBase;
|
|
55
|
+
const nextBaseScope = mergeScopePlatform(out.baseScope, opts.base);
|
|
56
|
+
if (nextBaseScope != null)
|
|
57
|
+
out.baseScope = nextBaseScope;
|
|
58
|
+
}
|
|
59
|
+
if (opts.comparison != null) {
|
|
60
|
+
const nextComp = mergeScopePlatform(out.comparisonExecutionScope, opts.comparison);
|
|
61
|
+
if (nextComp != null)
|
|
62
|
+
out.comparisonExecutionScope = nextComp;
|
|
63
|
+
const nextCov = mergeScopePlatform(out.coverageScope, opts.comparison);
|
|
64
|
+
if (nextCov != null)
|
|
65
|
+
out.coverageScope = nextCov;
|
|
66
|
+
}
|
|
67
|
+
return out;
|
|
68
|
+
}
|
|
69
|
+
export function prepareTruecoverageRequestBody(args) {
|
|
70
|
+
const raw = args ?? {};
|
|
71
|
+
const platformOpts = parseTruecoveragePlatformArgs(raw);
|
|
72
|
+
const stripped = stripTruecoveragePlatformShortcuts({ ...raw });
|
|
73
|
+
return applyTruecoveragePlatforms(stripped, platformOpts);
|
|
74
|
+
}
|