common-qa-mcp 0.7.0 → 0.7.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/dist/adapters/remoteMcp/adapter.js +1 -1
- package/dist/adapters/simplifyqa/adapter.d.ts +16 -28
- package/dist/adapters/simplifyqa/adapter.d.ts.map +1 -1
- package/dist/adapters/simplifyqa/adapter.js +226 -67
- package/dist/adapters/simplifyqa/adapter.js.map +1 -1
- package/dist/adapters/simplifyqa/mapper.d.ts.map +1 -1
- package/dist/adapters/simplifyqa/mapper.js +12 -1
- package/dist/adapters/simplifyqa/mapper.js.map +1 -1
- package/dist/adapters/types.d.ts +10 -2
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/domain/types.d.ts +14 -1
- package/dist/domain/types.d.ts.map +1 -1
- package/dist/server.js +1 -1
- package/dist/tools/discovery.tools.d.ts.map +1 -1
- package/dist/tools/discovery.tools.js +36 -9
- package/dist/tools/discovery.tools.js.map +1 -1
- package/dist/tools/markdown.d.ts.map +1 -1
- package/dist/tools/markdown.js +6 -1
- package/dist/tools/markdown.js.map +1 -1
- package/dist/tools/objects.tools.d.ts.map +1 -1
- package/dist/tools/objects.tools.js +46 -11
- package/dist/tools/objects.tools.js.map +1 -1
- package/dist/tools/run.tools.d.ts.map +1 -1
- package/dist/tools/run.tools.js +41 -5
- package/dist/tools/run.tools.js.map +1 -1
- package/dist/tools/testdata.tools.d.ts.map +1 -1
- package/dist/tools/testdata.tools.js +43 -4
- package/dist/tools/testdata.tools.js.map +1 -1
- package/package.json +1 -1
|
@@ -38,7 +38,7 @@ export class RemoteMcpAdapter {
|
|
|
38
38
|
async client() {
|
|
39
39
|
if (!this.clientPromise) {
|
|
40
40
|
this.clientPromise = (async () => {
|
|
41
|
-
const client = new Client({ name: 'common-qa-mcp', version: '0.7.
|
|
41
|
+
const client = new Client({ name: 'common-qa-mcp', version: '0.7.1' });
|
|
42
42
|
// The `as Transport` cast bridges exactOptionalPropertyTypes: StreamableHTTPClientTransport
|
|
43
43
|
// implements Transport, but the SDK's own .d.ts (built without EOPT) leaves its optional
|
|
44
44
|
// callbacks (onclose?/onerror?/onmessage?) without `| undefined`, which this project's EOPT
|
|
@@ -69,10 +69,6 @@ export declare class SimplifyQaAdapter {
|
|
|
69
69
|
getTestCase(id: string, versionId?: string): Promise<TestCase>;
|
|
70
70
|
private fetchRawTestcase;
|
|
71
71
|
private fetchStepsCollection;
|
|
72
|
-
/** For every FUNCTION step, resolve the referenced function's code + name via /tm/function search
|
|
73
|
-
* (batched by distinct functionId). Mutates `tc.steps[i].functionCall` in place with
|
|
74
|
-
* `testCaseCode`/`testCaseName`. Non-fatal on failure — the raw id still renders. Mirrors the
|
|
75
|
-
* Excel export builder in tcfn.service.js:2696-2703. */
|
|
76
72
|
private hydrateFunctionNames;
|
|
77
73
|
/** For every step with an objectRef, resolve the object's display name (`disname`) via
|
|
78
74
|
* /tm/object/search (batched by distinct objectId). Mutates `objectRef.name` in place. Mirrors the
|
|
@@ -138,15 +134,13 @@ export declare class SimplifyQaAdapter {
|
|
|
138
134
|
* Backend has no tx endpoint: on mid-walk failure the returned tree carries `failedAt`, and
|
|
139
135
|
* every node BEFORE that point is already persisted. */
|
|
140
136
|
createModule(input: ModuleCreateInput): Promise<ModuleSaved>;
|
|
137
|
+
private checkChildLinked;
|
|
141
138
|
/** Depth-first walk of a subtree. Stops at the first failure — everything already POSTed stays
|
|
142
139
|
* (no rollback endpoint upstream) and the failure is bubbled back on the root via `failedAt`. */
|
|
143
140
|
private createSubtree;
|
|
144
141
|
private postOneModule;
|
|
145
|
-
/** PUT /pm/module/:id — partial edit. Controller reads `projectId` off the body for its
|
|
146
|
-
* `add_module` privilege check (module.controller.js:64), so it MUST be sent even when unchanged;
|
|
147
|
-
* we default to the connected project. Only `name` / `description` are exposed — the controller
|
|
148
|
-
* ignores everything else the validator accepts (isRoot, parentId, childIds). */
|
|
149
142
|
updateModule(id: string, patch: ModuleUpdateInput): Promise<SavedRef>;
|
|
143
|
+
private reparentModule;
|
|
150
144
|
/** PATCH /pm/module — two-phase per module.controller.js:94. `confirm:false` returns the per-id
|
|
151
145
|
* dependency footprint (test cases, functions, params, objects, defects, user stories). `confirm:true`
|
|
152
146
|
* triggers the actual delete: server drops only ids with EMPTY dependencies; ids with references are
|
|
@@ -173,7 +167,11 @@ export declare class SimplifyQaAdapter {
|
|
|
173
167
|
* their assigned projects. Optional `projectId` narrows to that project's members; optional
|
|
174
168
|
* `search` is a case-insensitive regex over `name`. */
|
|
175
169
|
listUsers(q: UserQuery): Promise<ListResult<UserSummary>>;
|
|
176
|
-
getObject(id: string
|
|
170
|
+
getObject(id: string, opts?: {
|
|
171
|
+
enrichNames?: boolean;
|
|
172
|
+
}): Promise<QaObject>;
|
|
173
|
+
private enrichObjectNames;
|
|
174
|
+
private resolveParameterNames;
|
|
177
175
|
productUrlFor(entity: EntityRef): string;
|
|
178
176
|
private hop;
|
|
179
177
|
private requireHop;
|
|
@@ -323,25 +321,6 @@ export declare class SimplifyQaAdapter {
|
|
|
323
321
|
* (e.g. "click" for WEB + ANDROID) resolves to the right numeric id. */
|
|
324
322
|
private actionCatalogCache;
|
|
325
323
|
private actionCatalog;
|
|
326
|
-
/** POST /tm/object/createObjectSeq — get-or-create the shared object row by locator match. The
|
|
327
|
-
* backend does the dedup (`object.controller.js:268-370`) — same-locators reuses, same-disname-
|
|
328
|
-
* different-locators creates a suffixed one. Returns the numeric object id.
|
|
329
|
-
*
|
|
330
|
-
* ponytail: minimum body — no thumbnail_url / pageScreenShot_url / parameterId. The recording
|
|
331
|
-
* path enriches these; the tc_save path doesn't have screenshots to attach, and the object
|
|
332
|
-
* works for execution without them. */
|
|
333
|
-
/** GET-OR-CREATE by exact `disname`, scoped to the project — despite its name and the old comment
|
|
334
|
-
* here, `createObjectSeq` is a plain CREATE with no dedup of its own, so calling it unconditionally
|
|
335
|
-
* on every save minted a fresh duplicate object for the same recorded element every time (root
|
|
336
|
-
* cause of the "duplicate objects in the Object module" reports). Mirrors the SAME
|
|
337
|
-
* search-then-reuse pattern already trusted for parameters (findParameterId/getOrCreateParameter):
|
|
338
|
-
* 1. Exact case-insensitive name match found + SAME locator set → reuse the existing object as-is.
|
|
339
|
-
* 2. Exact name match found + DIFFERENT locators (the element's attributes drifted) → UPDATE the
|
|
340
|
-
* existing object in place (via updateObject's own locator-upsert) instead of creating a
|
|
341
|
-
* sibling — one entry per element, not a growing pile of near-identical copies.
|
|
342
|
-
* 3. No name match → create a new object, same as before.
|
|
343
|
-
* Does NOT catch a different name resolving to the same physical element (no cross-project
|
|
344
|
-
* locator-value search) — that would need a much broader, more expensive scan; out of scope here. */
|
|
345
324
|
private resolveObjectId;
|
|
346
325
|
/** For every automation step, resolve `actionId` (from action name + technology) and
|
|
347
326
|
* `objectId` (via createObjectSeq get-or-create) so the mapper can emit a valid step. Runs
|
|
@@ -434,6 +413,8 @@ export declare class SimplifyQaAdapter {
|
|
|
434
413
|
parameterNames?: string[];
|
|
435
414
|
/** Resolve to moduleId via listModules — the caller supplies a name, never an id. */
|
|
436
415
|
moduleName?: string;
|
|
416
|
+
}, opts?: {
|
|
417
|
+
enrichNames?: boolean;
|
|
437
418
|
}): Promise<QaObject>;
|
|
438
419
|
actionsCatalog(platform?: string): Promise<ActionDef[]>;
|
|
439
420
|
/** Fetch the default (template) iteration row for a TC. Fills gaps from the raw TC:
|
|
@@ -470,6 +451,13 @@ export declare class SimplifyQaAdapter {
|
|
|
470
451
|
* (`children[]`) instead of step details — a suite doc's `type` field flags it. start/stop still
|
|
471
452
|
* hop for v1. */
|
|
472
453
|
getRun(runId: string): Promise<RunStatus>;
|
|
454
|
+
private fetchExecDoc;
|
|
455
|
+
private fetchStepResults;
|
|
456
|
+
getSuiteChildRun(suiteRunId: string, child: {
|
|
457
|
+
testcaseId: string;
|
|
458
|
+
versionId?: string | undefined;
|
|
459
|
+
stepId?: string | undefined;
|
|
460
|
+
}): Promise<RunStatus>;
|
|
473
461
|
/** Most recent execution runId for a SUITE — same `/exec/execution/search` the /reports UI's
|
|
474
462
|
* current-executions view drives, filtered to `type=SUITE` + this suite's numeric id, sorted by
|
|
475
463
|
* id desc, limit 1. Returns the numeric run id (what `getRun` accepts), or null if the suite has
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/simplifyqa/adapter.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAC;AACzD,OAAO,KAAK,EAAE,iBAAiB,EAAU,MAAM,YAAY,CAAC;AAE5D,OAAO,KAAK,EAAE,UAAU,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC3D,OAAO,KAAK,EACV,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,gBAAgB,EAAE,WAAW,EAAE,aAAa,EAAE,SAAS,EAC5F,OAAO,EAAE,IAAI,EAAE,SAAS,EAAE,SAAS,EAAE,WAAW,EAAE,UAAU,EAC5D,OAAO,EAAE,YAAY,EAAE,YAAY,EAAE,cAAc,EAAE,aAAa,EAClE,OAAO,EAAE,WAAW,EAAE,aAAa,EAAE,eAAe,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EACxF,UAAU,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,iBAAiB,EAAE,kBAAkB,EAClF,YAAY,EAAE,WAAW,EAAE,aAAa,EAAmB,iBAAiB,EAAE,WAAW,EACzF,cAAc,EAAE,QAAQ,EAAE,YAAY,EACtC,cAAc,EAAE,UAAU,EAAE,MAAM,EAAE,SAAS,EAAE,SAAS,EAAE,uBAAuB,EACjF,6BAA6B,EAAE,QAAQ,EAAE,WAAW,EAAE,aAAa,EACnE,KAAK,EAAE,UAAU,EAAE,UAAU,EAAE,YAAY,EAAE,WAAW,EACxD,KAAK,EAAE,YAAY,EAAE,SAAS,EAAE,WAAW,EAAE,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,SAAS,EACpF,WAAW,EAAE,kBAAkB,EAAE,mBAAmB,EACrD,MAAM,uBAAuB,CAAC;AAY/B,kFAAkF;AAClF,MAAM,MAAM,mBAAmB,GAAG,IAAI,CAAC,iBAAiB,EAAE,WAAW,GAAG,cAAc,GAAG,UAAU,CAAC,CAAC;AA0MrG;;;;;;;;;;;;GAYG;AACH,qBAAa,iBAAiB;IAe1B,OAAO,CAAC,QAAQ,CAAC,GAAG;IAdtB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAS;IAC9B,OAAO,CAAC,QAAQ,CAAiC;IAOjD,OAAO,CAAC,YAAY,CAAmC;IAGvD,OAAO,CAAC,oBAAoB,CAA0E;gBAGnF,GAAG,EAAE,iBAAiB,EACvC,SAAS,CAAC,EAAE,mBAAmB;IAgBjC,OAAO,CAAC,OAAO;IAOf,OAAO,CAAC,gBAAgB;IASxB,OAAO,CAAC,UAAU;IAmBlB;;;;uDAImD;IAC7C,IAAI,IAAI,OAAO,CAAC,WAAW,CAAC;IAkBlC;;;;;;;;;;yFAUqF;IAC/E,YAAY,IAAI,OAAO,CAAC,UAAU,CAAC,cAAc,CAAC,CAAC;YAK3C,mBAAmB;IA2BjC;;;;;oDAKgD;YAClC,gBAAgB;YAehB,kBAAkB;IAoBhC;;8DAE0D;IAC1D,OAAO,CAAC,SAAS;IAqBX,aAAa,CAAC,CAAC,EAAE,OAAO,GAAG,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC;IA0B/D;8EAC0E;IAC1E,OAAO,CAAC,iBAAiB;IAQzB;;;sGAGkG;IAC5F,WAAW,CAAC,EAAE,EAAE,MAAM,EAAE,SAAS,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,CAAC;YAgCtD,gBAAgB;YAOhB,oBAAoB;
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../../src/adapters/simplifyqa/adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -514,10 +514,6 @@ export class SimplifyQaAdapter {
|
|
|
514
514
|
const rows = Array.isArray(body) ? body : Array.isArray(body?.data) ? body.data : [];
|
|
515
515
|
return rows;
|
|
516
516
|
}
|
|
517
|
-
/** For every FUNCTION step, resolve the referenced function's code + name via /tm/function search
|
|
518
|
-
* (batched by distinct functionId). Mutates `tc.steps[i].functionCall` in place with
|
|
519
|
-
* `testCaseCode`/`testCaseName`. Non-fatal on failure — the raw id still renders. Mirrors the
|
|
520
|
-
* Excel export builder in tcfn.service.js:2696-2703. */
|
|
521
517
|
async hydrateFunctionNames(tc) {
|
|
522
518
|
const ids = new Set();
|
|
523
519
|
for (const s of tc.steps) {
|
|
@@ -543,16 +539,33 @@ export class SimplifyQaAdapter {
|
|
|
543
539
|
continue;
|
|
544
540
|
byId.set(rid, { code: str(r, 'code'), name: str(r, 'name', 'title') ?? '' });
|
|
545
541
|
}
|
|
542
|
+
const versionNamesById = new Map();
|
|
543
|
+
await Promise.all([...ids].map(async (fnId) => {
|
|
544
|
+
try {
|
|
545
|
+
const versionRows = await this.fetchFunctionVersionRows(fnId);
|
|
546
|
+
const versions = toVersionEntries(versionRows);
|
|
547
|
+
versionNamesById.set(fnId, new Map(versions.map((v) => [v.id, v.name])));
|
|
548
|
+
}
|
|
549
|
+
catch {
|
|
550
|
+
// Non-fatal per function: that step's version falls back to the bare uuid.
|
|
551
|
+
}
|
|
552
|
+
}));
|
|
546
553
|
for (const s of tc.steps) {
|
|
547
554
|
if (s.stepType !== 'function' || !s.functionCall)
|
|
548
555
|
continue;
|
|
549
556
|
const hit = byId.get(s.functionCall.testCaseId);
|
|
550
|
-
if (
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
557
|
+
if (hit) {
|
|
558
|
+
if (hit.code)
|
|
559
|
+
s.functionCall.testCaseCode = hit.code;
|
|
560
|
+
if (hit.name)
|
|
561
|
+
s.functionCall.testCaseName = hit.name;
|
|
562
|
+
}
|
|
563
|
+
const versionId = s.functionCall.versionId;
|
|
564
|
+
if (versionId) {
|
|
565
|
+
const versionName = versionNamesById.get(s.functionCall.testCaseId)?.get(versionId);
|
|
566
|
+
if (versionName)
|
|
567
|
+
s.functionCall.versionName = versionName;
|
|
568
|
+
}
|
|
556
569
|
}
|
|
557
570
|
}
|
|
558
571
|
catch {
|
|
@@ -1023,11 +1036,27 @@ export class SimplifyQaAdapter {
|
|
|
1023
1036
|
* every node BEFORE that point is already persisted. */
|
|
1024
1037
|
async createModule(input) {
|
|
1025
1038
|
const root = await this.postOneModule(input.name, input.isRoot, input.projectId, input.description, input.parentId);
|
|
1039
|
+
if (!input.isRoot && input.parentId) {
|
|
1040
|
+
root.linkWarning = await this.checkChildLinked(input.parentId, root.id);
|
|
1041
|
+
}
|
|
1026
1042
|
if (input.children?.length) {
|
|
1027
1043
|
root.children = await this.createSubtree(input.children, root.id, input.projectId, input.name, root);
|
|
1028
1044
|
}
|
|
1029
1045
|
return root;
|
|
1030
1046
|
}
|
|
1047
|
+
async checkChildLinked(parentId, childId) {
|
|
1048
|
+
try {
|
|
1049
|
+
const parent = await this.getModule(parentId);
|
|
1050
|
+
const numChildId = Number.parseInt(childId, 10);
|
|
1051
|
+
if (parent.childIds?.includes(numChildId))
|
|
1052
|
+
return undefined;
|
|
1053
|
+
return `Created with parentId=${parentId}, but a fresh read of module ${parentId} does not yet list ` +
|
|
1054
|
+
`${childId} in its childIds — it may not appear under its parent in the Module screen tree until that catches up.`;
|
|
1055
|
+
}
|
|
1056
|
+
catch {
|
|
1057
|
+
return undefined;
|
|
1058
|
+
}
|
|
1059
|
+
}
|
|
1031
1060
|
/** Depth-first walk of a subtree. Stops at the first failure — everything already POSTed stays
|
|
1032
1061
|
* (no rollback endpoint upstream) and the failure is bubbled back on the root via `failedAt`. */
|
|
1033
1062
|
async createSubtree(children, parentId, projectId, parentPath, root) {
|
|
@@ -1044,6 +1073,7 @@ export class SimplifyQaAdapter {
|
|
|
1044
1073
|
root.failedAt = { path, error: e instanceof Error ? e.message : String(e) };
|
|
1045
1074
|
return out;
|
|
1046
1075
|
}
|
|
1076
|
+
saved.linkWarning = await this.checkChildLinked(parentId, saved.id);
|
|
1047
1077
|
if (child.children?.length) {
|
|
1048
1078
|
saved.children = await this.createSubtree(child.children, saved.id, projectId, path, root);
|
|
1049
1079
|
}
|
|
@@ -1065,23 +1095,56 @@ export class SimplifyQaAdapter {
|
|
|
1065
1095
|
const raw = await this.http.postJson('/pm/module', payload);
|
|
1066
1096
|
return toModuleSaved(raw, name);
|
|
1067
1097
|
}
|
|
1068
|
-
/** PUT /pm/module/:id — partial edit. Controller reads `projectId` off the body for its
|
|
1069
|
-
* `add_module` privilege check (module.controller.js:64), so it MUST be sent even when unchanged;
|
|
1070
|
-
* we default to the connected project. Only `name` / `description` are exposed — the controller
|
|
1071
|
-
* ignores everything else the validator accepts (isRoot, parentId, childIds). */
|
|
1072
1098
|
async updateModule(id, patch) {
|
|
1073
|
-
const projectId = patch.projectId
|
|
1074
|
-
? Number.parseInt(numericId(patch.projectId), 10)
|
|
1075
|
-
: this.requireProjectId();
|
|
1076
|
-
const body = { projectId };
|
|
1077
|
-
if (patch.name !== undefined)
|
|
1078
|
-
body['name'] = patch.name;
|
|
1079
|
-
if (patch.description !== undefined)
|
|
1080
|
-
body['description'] = patch.description;
|
|
1081
1099
|
const resolvedId = numericId(id);
|
|
1082
|
-
|
|
1100
|
+
let raw;
|
|
1101
|
+
if (patch.name !== undefined || patch.description !== undefined) {
|
|
1102
|
+
const projectId = patch.projectId
|
|
1103
|
+
? Number.parseInt(numericId(patch.projectId), 10)
|
|
1104
|
+
: this.requireProjectId();
|
|
1105
|
+
const body = { projectId };
|
|
1106
|
+
if (patch.name !== undefined)
|
|
1107
|
+
body['name'] = patch.name;
|
|
1108
|
+
if (patch.description !== undefined)
|
|
1109
|
+
body['description'] = patch.description;
|
|
1110
|
+
raw = await this.http.putJson(`/pm/module/${resolvedId}`, body);
|
|
1111
|
+
}
|
|
1112
|
+
if (patch.parentId !== undefined) {
|
|
1113
|
+
await this.reparentModule(resolvedId, patch.parentId);
|
|
1114
|
+
}
|
|
1083
1115
|
return toSavedRef(raw ?? { id: resolvedId }, false);
|
|
1084
1116
|
}
|
|
1117
|
+
async reparentModule(id, newParentId) {
|
|
1118
|
+
if (newParentId === '') {
|
|
1119
|
+
await this.http.putJson(`/pm/module/bulkupdate/${id}`, { isRoot: true });
|
|
1120
|
+
return;
|
|
1121
|
+
}
|
|
1122
|
+
const targetId = numericId(newParentId);
|
|
1123
|
+
if (targetId === id) {
|
|
1124
|
+
throw new Error(`Cannot set module ${id} as its own parent.`);
|
|
1125
|
+
}
|
|
1126
|
+
const all = await this.listModules();
|
|
1127
|
+
const childrenOf = new Map();
|
|
1128
|
+
for (const m of all)
|
|
1129
|
+
if (m.parentId)
|
|
1130
|
+
childrenOf.set(m.parentId, [...(childrenOf.get(m.parentId) ?? []), m.id]);
|
|
1131
|
+
const descendants = new Set();
|
|
1132
|
+
const stack = [...(childrenOf.get(id) ?? [])];
|
|
1133
|
+
while (stack.length) {
|
|
1134
|
+
const next = stack.pop();
|
|
1135
|
+
if (descendants.has(next))
|
|
1136
|
+
continue;
|
|
1137
|
+
descendants.add(next);
|
|
1138
|
+
stack.push(...(childrenOf.get(next) ?? []));
|
|
1139
|
+
}
|
|
1140
|
+
if (descendants.has(targetId)) {
|
|
1141
|
+
throw new Error(`Cannot move module ${id} under ${targetId} — it is already a descendant of ${id} (would detach the subtree).`);
|
|
1142
|
+
}
|
|
1143
|
+
if (!all.some((m) => m.id === targetId)) {
|
|
1144
|
+
throw new Error(`Parent module ${targetId} not found.`);
|
|
1145
|
+
}
|
|
1146
|
+
await this.http.putJson(`/pm/module/bulkupdate/${id}`, { parentId: Number.parseInt(targetId, 10), isRoot: false });
|
|
1147
|
+
}
|
|
1085
1148
|
/** PATCH /pm/module — two-phase per module.controller.js:94. `confirm:false` returns the per-id
|
|
1086
1149
|
* dependency footprint (test cases, functions, params, objects, defects, user stories). `confirm:true`
|
|
1087
1150
|
* triggers the actual delete: server drops only ids with EMPTY dependencies; ids with references are
|
|
@@ -1195,12 +1258,55 @@ export class SimplifyQaAdapter {
|
|
|
1195
1258
|
return withTotal(users, raw);
|
|
1196
1259
|
}
|
|
1197
1260
|
// ---------------------------------------------------------------------- Objects (read)
|
|
1198
|
-
async getObject(id) {
|
|
1261
|
+
async getObject(id, opts) {
|
|
1199
1262
|
const raw = await this.http.getJson(`/tm/object/${numericId(id)}`);
|
|
1200
1263
|
let doc = raw?.data ?? raw;
|
|
1201
1264
|
if (Array.isArray(doc))
|
|
1202
1265
|
doc = doc.length > 0 ? doc[0] : {};
|
|
1203
|
-
|
|
1266
|
+
const obj = toObject(doc && typeof doc === 'object' ? doc : {});
|
|
1267
|
+
if (opts?.enrichNames)
|
|
1268
|
+
await this.enrichObjectNames(obj);
|
|
1269
|
+
return obj;
|
|
1270
|
+
}
|
|
1271
|
+
async enrichObjectNames(obj) {
|
|
1272
|
+
if (obj.moduleId) {
|
|
1273
|
+
try {
|
|
1274
|
+
const modules = await this.listModules();
|
|
1275
|
+
const match = modules.find((m) => m.id === obj.moduleId);
|
|
1276
|
+
if (match)
|
|
1277
|
+
obj.moduleName = match.name;
|
|
1278
|
+
}
|
|
1279
|
+
catch { /* best-effort */ }
|
|
1280
|
+
}
|
|
1281
|
+
if (obj.parameterIds?.length) {
|
|
1282
|
+
const names = await this.resolveParameterNames(obj.parameterIds);
|
|
1283
|
+
const resolved = obj.parameterIds.map((pid) => names.get(pid)).filter((n) => !!n);
|
|
1284
|
+
if (resolved.length)
|
|
1285
|
+
obj.parameterNames = resolved;
|
|
1286
|
+
}
|
|
1287
|
+
}
|
|
1288
|
+
async resolveParameterNames(ids) {
|
|
1289
|
+
const map = new Map();
|
|
1290
|
+
const numIds = ids.map((i) => Number.parseInt(i, 10)).filter(Number.isFinite);
|
|
1291
|
+
if (!numIds.length)
|
|
1292
|
+
return map;
|
|
1293
|
+
try {
|
|
1294
|
+
const projectId = this.requireProjectId();
|
|
1295
|
+
const body = this.searchBody([
|
|
1296
|
+
{ column: 'projectId', value: projectId },
|
|
1297
|
+
{ column: 'id', value: numIds, regEx: false },
|
|
1298
|
+
]);
|
|
1299
|
+
const raw = await this.http.postJson('/tm/parameter/search', body);
|
|
1300
|
+
const rows = pickArray(raw, 'data', 'content');
|
|
1301
|
+
for (const row of rows) {
|
|
1302
|
+
const rid = str(row, 'id', '_id', 'parameterId');
|
|
1303
|
+
const name = str(row, 'name');
|
|
1304
|
+
if (rid && name)
|
|
1305
|
+
map.set(rid, name);
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
catch { /* best-effort */ }
|
|
1309
|
+
return map;
|
|
1204
1310
|
}
|
|
1205
1311
|
// ---------------------------------------------------------------------- Deep links
|
|
1206
1312
|
productUrlFor(entity) {
|
|
@@ -2249,25 +2355,6 @@ export class SimplifyQaAdapter {
|
|
|
2249
2355
|
})().catch((e) => { this.actionCatalogCache = null; throw e; });
|
|
2250
2356
|
return this.actionCatalogCache;
|
|
2251
2357
|
}
|
|
2252
|
-
/** POST /tm/object/createObjectSeq — get-or-create the shared object row by locator match. The
|
|
2253
|
-
* backend does the dedup (`object.controller.js:268-370`) — same-locators reuses, same-disname-
|
|
2254
|
-
* different-locators creates a suffixed one. Returns the numeric object id.
|
|
2255
|
-
*
|
|
2256
|
-
* ponytail: minimum body — no thumbnail_url / pageScreenShot_url / parameterId. The recording
|
|
2257
|
-
* path enriches these; the tc_save path doesn't have screenshots to attach, and the object
|
|
2258
|
-
* works for execution without them. */
|
|
2259
|
-
/** GET-OR-CREATE by exact `disname`, scoped to the project — despite its name and the old comment
|
|
2260
|
-
* here, `createObjectSeq` is a plain CREATE with no dedup of its own, so calling it unconditionally
|
|
2261
|
-
* on every save minted a fresh duplicate object for the same recorded element every time (root
|
|
2262
|
-
* cause of the "duplicate objects in the Object module" reports). Mirrors the SAME
|
|
2263
|
-
* search-then-reuse pattern already trusted for parameters (findParameterId/getOrCreateParameter):
|
|
2264
|
-
* 1. Exact case-insensitive name match found + SAME locator set → reuse the existing object as-is.
|
|
2265
|
-
* 2. Exact name match found + DIFFERENT locators (the element's attributes drifted) → UPDATE the
|
|
2266
|
-
* existing object in place (via updateObject's own locator-upsert) instead of creating a
|
|
2267
|
-
* sibling — one entry per element, not a growing pile of near-identical copies.
|
|
2268
|
-
* 3. No name match → create a new object, same as before.
|
|
2269
|
-
* Does NOT catch a different name resolving to the same physical element (no cross-project
|
|
2270
|
-
* locator-value search) — that would need a much broader, more expensive scan; out of scope here. */
|
|
2271
2358
|
async resolveObjectId(objectRef, projectId, moduleId, technology, objectTemplateId) {
|
|
2272
2359
|
const name = (objectRef.name ?? '').trim();
|
|
2273
2360
|
const incomingLocators = objectRef.locators ?? [];
|
|
@@ -2620,6 +2707,26 @@ export class SimplifyQaAdapter {
|
|
|
2620
2707
|
throw new Error('createObject: objectType is required (e.g. "WEB", "ANDROID") — it selects the object template ' +
|
|
2621
2708
|
'and cannot be changed after the object is created.');
|
|
2622
2709
|
}
|
|
2710
|
+
const wantedName = (o.name ?? '').trim();
|
|
2711
|
+
if (wantedName) {
|
|
2712
|
+
try {
|
|
2713
|
+
const candidates = await this.searchObjects({ query: wantedName, limit: 20 });
|
|
2714
|
+
const existing = candidates.find((c) => c.name.trim().toLowerCase() === wantedName.toLowerCase());
|
|
2715
|
+
if (existing?.id) {
|
|
2716
|
+
const key = (l) => `${l.name}::${l.value}`;
|
|
2717
|
+
const existingKeys = new Set(existing.locators.map(key));
|
|
2718
|
+
const incomingKeys = new Set((o.locators ?? []).map(key));
|
|
2719
|
+
const sameLocators = existingKeys.size === incomingKeys.size
|
|
2720
|
+
&& [...existingKeys].every((k) => incomingKeys.has(k));
|
|
2721
|
+
return sameLocators || !o.locators?.length
|
|
2722
|
+
? existing
|
|
2723
|
+
: await this.updateObject(existing.id, { locators: o.locators });
|
|
2724
|
+
}
|
|
2725
|
+
}
|
|
2726
|
+
catch {
|
|
2727
|
+
// Lookup failed — fall through to create rather than block the save over this.
|
|
2728
|
+
}
|
|
2729
|
+
}
|
|
2623
2730
|
const projectId = this.requireProjectId();
|
|
2624
2731
|
const objecttemplateId = await this.resolveObjectTemplateId(o.objectType);
|
|
2625
2732
|
const moduleId = await this.resolveDefaultModuleId();
|
|
@@ -2707,7 +2814,7 @@ export class SimplifyQaAdapter {
|
|
|
2707
2814
|
* attribute set is even valid for this object), so editing them here — outside the create flow — is
|
|
2708
2815
|
* out of scope; changing them means creating a new object, not "updating" this one.
|
|
2709
2816
|
*/
|
|
2710
|
-
async updateObject(id, changes) {
|
|
2817
|
+
async updateObject(id, changes, opts) {
|
|
2711
2818
|
const numId = numericId(id);
|
|
2712
2819
|
const raw = await this.http.getJson(`/tm/object/${numId}`);
|
|
2713
2820
|
const doc = (raw?.data && typeof raw.data === 'object' ? raw.data : raw) ?? {};
|
|
@@ -2771,7 +2878,10 @@ export class SimplifyQaAdapter {
|
|
|
2771
2878
|
};
|
|
2772
2879
|
const res = await this.http.putJson(`/tm/object/${numId}`, body);
|
|
2773
2880
|
const updated = (res?.data && typeof res.data === 'object' ? res.data : res) ?? doc;
|
|
2774
|
-
|
|
2881
|
+
const obj = toObject(updated);
|
|
2882
|
+
if (opts?.enrichNames)
|
|
2883
|
+
await this.enrichObjectNames(obj);
|
|
2884
|
+
return obj;
|
|
2775
2885
|
}
|
|
2776
2886
|
// ---------------------------------------------------------------------- Actions catalog
|
|
2777
2887
|
async actionsCatalog(platform) {
|
|
@@ -2825,8 +2935,9 @@ export class SimplifyQaAdapter {
|
|
|
2825
2935
|
const meta = await this.fetchParameterMeta(pid);
|
|
2826
2936
|
if (!meta)
|
|
2827
2937
|
continue; // parameter deleted — skip
|
|
2828
|
-
const
|
|
2829
|
-
|
|
2938
|
+
const isProtected = meta.protected || looksSensitive(meta.name);
|
|
2939
|
+
const seed = isProtected ? (rawValue ? '*****' : '(empty)') : rawValue;
|
|
2940
|
+
parameters.push({ paramId: pid, name: meta.name, seed, ...(isProtected ? { protected: true } : {}) });
|
|
2830
2941
|
}
|
|
2831
2942
|
}
|
|
2832
2943
|
return { tcId: q.tcId, versionId: versionId, environmentType: env, parameters };
|
|
@@ -3005,23 +3116,19 @@ export class SimplifyQaAdapter {
|
|
|
3005
3116
|
// Top-level execution doc (carries `type` = 'TC' or 'SUITE', and `executionItems[]` for a suite).
|
|
3006
3117
|
// One extra POST per getRun call; a suite short-circuits here so no /exec/report is needed.
|
|
3007
3118
|
if (Number.isFinite(runIdNum)) {
|
|
3008
|
-
const
|
|
3009
|
-
searchFields: [
|
|
3010
|
-
{ column: 'id', value: runIdNum, regEx: false },
|
|
3011
|
-
{ column: 'projectId', value: projectId, regEx: false },
|
|
3012
|
-
{ column: 'deleted', value: false },
|
|
3013
|
-
],
|
|
3014
|
-
startIndex: 0,
|
|
3015
|
-
limit: 1,
|
|
3016
|
-
};
|
|
3017
|
-
const execRaw = await this.http.postJson('/exec/execution/search', execBody);
|
|
3018
|
-
const execDoc = pickArray(execRaw, 'data', 'content', 'executions')[0];
|
|
3119
|
+
const execDoc = await this.fetchExecDoc(runIdNum, projectId);
|
|
3019
3120
|
if (execDoc && String(execDoc.type ?? '').toUpperCase() === 'SUITE') {
|
|
3020
3121
|
const items = Array.isArray(execDoc.executionItems) ? execDoc.executionItems : [];
|
|
3021
3122
|
const children = items.map((it) => {
|
|
3123
|
+
const testcaseId = str(it, 'testcaseId');
|
|
3124
|
+
const versionId = str(it, 'versionId');
|
|
3125
|
+
const stepId = str(it, 'stepId');
|
|
3022
3126
|
const child = {
|
|
3023
|
-
id:
|
|
3127
|
+
id: testcaseId ?? String(it?.id ?? ''),
|
|
3024
3128
|
state: mapRunState(str(it, 'status') ?? ''),
|
|
3129
|
+
...(testcaseId ? { testcaseId } : {}),
|
|
3130
|
+
...(versionId ? { versionId } : {}),
|
|
3131
|
+
...(stepId ? { stepId } : {}),
|
|
3025
3132
|
};
|
|
3026
3133
|
const name = str(it, 'name');
|
|
3027
3134
|
if (name)
|
|
@@ -3054,14 +3161,33 @@ export class SimplifyQaAdapter {
|
|
|
3054
3161
|
}
|
|
3055
3162
|
const executionRunId = str(chosen, 'id', '_id') ?? '';
|
|
3056
3163
|
const parentId = Number(chosen?.executionItemId ?? 0);
|
|
3164
|
+
const stepResults = await this.fetchStepResults(runIdNum, executionRunId, parentId, projectId);
|
|
3165
|
+
return {
|
|
3166
|
+
runId,
|
|
3167
|
+
state: mapRunState(str(chosen, 'status') ?? ''),
|
|
3168
|
+
stepResults,
|
|
3169
|
+
reportUrl: `${base}/user/reports/reports-page?type=TESTCASE&parentId=${parentId}&id=${runIdNum}&projectId=${projectId}`,
|
|
3170
|
+
};
|
|
3171
|
+
}
|
|
3172
|
+
async fetchExecDoc(runIdNum, projectId) {
|
|
3173
|
+
const execBody = {
|
|
3174
|
+
searchFields: [
|
|
3175
|
+
{ column: 'id', value: runIdNum, regEx: false },
|
|
3176
|
+
{ column: 'projectId', value: projectId, regEx: false },
|
|
3177
|
+
{ column: 'deleted', value: false },
|
|
3178
|
+
],
|
|
3179
|
+
startIndex: 0,
|
|
3180
|
+
limit: 1,
|
|
3181
|
+
};
|
|
3182
|
+
const execRaw = await this.http.postJson('/exec/execution/search', execBody);
|
|
3183
|
+
return pickArray(execRaw, 'data', 'content', 'executions')[0];
|
|
3184
|
+
}
|
|
3185
|
+
async fetchStepResults(executionId, executionRunId, parentId, projectId) {
|
|
3057
3186
|
const stepsResp = await this.http.postJson('/reports/execution/getstepResult', {
|
|
3058
|
-
executionId
|
|
3059
|
-
executionRunId,
|
|
3060
|
-
parentId,
|
|
3061
|
-
projectId,
|
|
3187
|
+
executionId, executionRunId, parentId, projectId,
|
|
3062
3188
|
});
|
|
3063
3189
|
const rawSteps = Array.isArray(stepsResp?.data) ? stepsResp.data : [];
|
|
3064
|
-
|
|
3190
|
+
return rawSteps.map((s) => {
|
|
3065
3191
|
const step = {
|
|
3066
3192
|
n: typeof s?.seq === 'number' ? s.seq : 0,
|
|
3067
3193
|
description: String(s?.description ?? ''),
|
|
@@ -3091,11 +3217,44 @@ export class SimplifyQaAdapter {
|
|
|
3091
3217
|
}
|
|
3092
3218
|
return step;
|
|
3093
3219
|
});
|
|
3220
|
+
}
|
|
3221
|
+
async getSuiteChildRun(suiteRunId, child) {
|
|
3222
|
+
const projectId = this.requireProjectId();
|
|
3223
|
+
const runIdNum = Number.parseInt(numericId(suiteRunId), 10);
|
|
3224
|
+
const execDoc = await this.fetchExecDoc(runIdNum, projectId);
|
|
3225
|
+
if (!execDoc)
|
|
3226
|
+
throw new Error(`Suite run ${suiteRunId} not found.`);
|
|
3227
|
+
const suiteNum = Number(execDoc.executionTypeId ?? 0);
|
|
3228
|
+
const body = {
|
|
3229
|
+
type: 'SU',
|
|
3230
|
+
projectId,
|
|
3231
|
+
parentId: suiteNum,
|
|
3232
|
+
executionId: runIdNum,
|
|
3233
|
+
tcId: Number.parseInt(numericId(child.testcaseId), 10),
|
|
3234
|
+
...(child.versionId ? { tcVersionId: child.versionId } : {}),
|
|
3235
|
+
...(child.stepId ? { stepId: child.stepId } : {}),
|
|
3236
|
+
};
|
|
3237
|
+
const raw = await this.http.postJson('/reports/execution/getExecutionRuns', body);
|
|
3238
|
+
const runs = Array.isArray(raw?.data) ? raw.data : [];
|
|
3239
|
+
const base = (this.cfg.baseUrl ?? '').replace(/\/+$/, '');
|
|
3240
|
+
if (!runs.length) {
|
|
3241
|
+
return { runId: suiteRunId, state: 'queued' };
|
|
3242
|
+
}
|
|
3243
|
+
let chosen = runs[0];
|
|
3244
|
+
for (const r of runs) {
|
|
3245
|
+
if (typeof r?.status === 'string' && r.status.toUpperCase() === 'FAILED') {
|
|
3246
|
+
chosen = r;
|
|
3247
|
+
break;
|
|
3248
|
+
}
|
|
3249
|
+
}
|
|
3250
|
+
const executionRunId = str(chosen, 'id', '_id') ?? '';
|
|
3251
|
+
const parentId = Number(chosen?.executionItemId ?? 0);
|
|
3252
|
+
const stepResults = await this.fetchStepResults(runIdNum, executionRunId, parentId, projectId);
|
|
3094
3253
|
return {
|
|
3095
|
-
runId,
|
|
3254
|
+
runId: suiteRunId,
|
|
3096
3255
|
state: mapRunState(str(chosen, 'status') ?? ''),
|
|
3097
3256
|
stepResults,
|
|
3098
|
-
reportUrl: `${base}/user/reports/reports-page?type=TESTCASE&parentId=${parentId}&id=${
|
|
3257
|
+
reportUrl: `${base}/user/reports/reports-page?type=TESTCASE&parentId=${parentId}&id=${runIdNum}&projectId=${projectId}`,
|
|
3099
3258
|
};
|
|
3100
3259
|
}
|
|
3101
3260
|
/** Most recent execution runId for a SUITE — same `/exec/execution/search` the /reports UI's
|