@allurereport/plugin-testops 3.6.1 → 3.6.2

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/client.d.ts CHANGED
@@ -27,7 +27,7 @@ export declare class TestOpsClient {
27
27
  startUpload(ci: CiDescriptor): Promise<void>;
28
28
  stopUpload(ci: CiDescriptor, status: TestStatus): Promise<void>;
29
29
  createLaunch(launchName: string, launchTags: string[]): Promise<void>;
30
- createSession(environment?: Record<string, any>): Promise<void>;
30
+ createSession(environment?: Record<string, unknown>): Promise<void>;
31
31
  get namedEnvs(): MapIterator<TestOpsNamedEnv>;
32
32
  getNamedEnvFor(id: string): TestOpsNamedEnv | undefined;
33
33
  createNamedEnvs(environments: EnvironmentIdentity[], onProgress?: (percent: number, total: number) => void): Promise<void>;
package/dist/client.js CHANGED
@@ -16,6 +16,7 @@ import { chunk } from "lodash-es";
16
16
  import pLimit from "p-limit";
17
17
  import { bold } from "yoctocolors";
18
18
  import { Logger } from "./logger.js";
19
+ import { toUploadFixturesResultsDto, toUploadResultsDto } from "./uploaderDto.js";
19
20
  class TestOpsClientError extends AxiosError {
20
21
  }
21
22
  const CHUNK_SIZE = 100;
@@ -356,40 +357,33 @@ export class TestOpsClient {
356
357
  }
357
358
  }
358
359
  _TestOpsClient_logger = new WeakMap(), _TestOpsClient_accessToken = new WeakMap(), _TestOpsClient_projectId = new WeakMap(), _TestOpsClient_oauthToken = new WeakMap(), _TestOpsClient_client = new WeakMap(), _TestOpsClient_launch = new WeakMap(), _TestOpsClient_session = new WeakMap(), _TestOpsClient_uploadInProgress = new WeakMap(), _TestOpsClient_uploadLimit = new WeakMap(), _TestOpsClient_namedEnvsIdsByEnv = new WeakMap(), _TestOpsClient_instances = new WeakSet(), _TestOpsClient_postTestResultsChunk = async function _TestOpsClient_postTestResultsChunk(trsChunk) {
359
- const { data } = await __classPrivateFieldGet(this, _TestOpsClient_client, "f").post("/api/upload/test-result", {
360
- testSessionId: __classPrivateFieldGet(this, _TestOpsClient_session, "f").id,
361
- results: trsChunk.map((testResult) => {
362
- const extendedTestResult = {
363
- ...testResult,
364
- uuid: testResult.id,
365
- };
366
- const namedEnvironment = !!testResult.environment && this.getNamedEnvFor(testResult.environment);
367
- if (namedEnvironment) {
368
- extendedTestResult.namedEnv = { id: namedEnvironment.id };
369
- }
370
- if (typeof extendedTestResult.category?.externalId === "string" ||
371
- typeof extendedTestResult.category?.externalId === "number") {
372
- const category = extendedTestResult.category;
373
- extendedTestResult.category = {
374
- externalId: category.externalId,
375
- };
376
- if (category.grouping && category.grouping.length > 0) {
377
- extendedTestResult.category.grouping = category.grouping;
378
- }
379
- }
380
- const error = extendedTestResult.error;
381
- if (typeof error?.message === "string") {
382
- extendedTestResult.message = error.message;
383
- }
384
- if (typeof error?.trace === "string") {
385
- extendedTestResult.trace = error.trace;
386
- }
387
- return extendedTestResult;
388
- }),
389
- }, { headers: { "Content-Type": "application/json" } });
360
+ const extendedChunk = trsChunk.map((testResult) => {
361
+ const extendedTestResult = {
362
+ ...testResult,
363
+ uuid: testResult.id,
364
+ };
365
+ const namedEnvironment = !!testResult.environment && this.getNamedEnvFor(testResult.environment);
366
+ if (namedEnvironment) {
367
+ extendedTestResult.namedEnv = { id: namedEnvironment.id };
368
+ }
369
+ const error = extendedTestResult.error;
370
+ if (typeof error?.message === "string") {
371
+ extendedTestResult.message = error.message;
372
+ }
373
+ if (typeof error?.trace === "string") {
374
+ extendedTestResult.trace = error.trace;
375
+ }
376
+ return extendedTestResult;
377
+ });
378
+ const body = toUploadResultsDto(__classPrivateFieldGet(this, _TestOpsClient_session, "f").id, extendedChunk);
379
+ const { data } = await __classPrivateFieldGet(this, _TestOpsClient_client, "f").post("/api/upload/test-result", body, {
380
+ headers: { "Content-Type": "application/json" },
381
+ });
390
382
  const reportIdsToTestOpsIds = {};
391
383
  for (const { id, uuid } of data.results ?? []) {
392
- reportIdsToTestOpsIds[uuid] = id;
384
+ if (typeof uuid === "string" && typeof id === "number") {
385
+ reportIdsToTestOpsIds[uuid] = id;
386
+ }
393
387
  }
394
388
  return reportIdsToTestOpsIds;
395
389
  }, _TestOpsClient_uploadChunkAttachmentsAndFixtures = async function _TestOpsClient_uploadChunkAttachmentsAndFixtures(trsChunk, reportIdsToTestOpsIds, attachmentsResolver, fixturesResolver, uploadLimitFn, onProgress) {
@@ -435,7 +429,6 @@ _TestOpsClient_logger = new WeakMap(), _TestOpsClient_accessToken = new WeakMap(
435
429
  }, _TestOpsClient_uploadFixturesForResult = async function _TestOpsClient_uploadFixturesForResult(testOpsResultId, fixtures) {
436
430
  if (fixtures.length === 0)
437
431
  return;
438
- await __classPrivateFieldGet(this, _TestOpsClient_client, "f").post(`/api/upload/test-result/${testOpsResultId}/test-fixture-result`, {
439
- fixtures,
440
- });
432
+ const body = toUploadFixturesResultsDto(fixtures);
433
+ await __classPrivateFieldGet(this, _TestOpsClient_client, "f").post(`/api/upload/test-result/${testOpsResultId}/test-fixture-result`, body);
441
434
  };
package/dist/model.d.ts CHANGED
@@ -13,6 +13,136 @@ export type UploadCategory = {
13
13
  expand?: boolean;
14
14
  hide?: boolean;
15
15
  };
16
+ export type UploadTestStatus = "failed" | "broken" | "passed" | "skipped" | "unknown";
17
+ export type UploadTestResultCategoryGroupingDto = {
18
+ key?: string;
19
+ value?: string;
20
+ name?: string;
21
+ };
22
+ export type UploadTestResultCategoryDto = {
23
+ id?: number;
24
+ externalId?: string;
25
+ grouping?: UploadTestResultCategoryGroupingDto[];
26
+ };
27
+ export type UploadTestResultNamedEnvDto = {
28
+ id?: number;
29
+ externalId?: string;
30
+ };
31
+ export type UploadAttachmentDto = {
32
+ name?: string;
33
+ originalFileName?: string;
34
+ contentType?: string;
35
+ contentLength?: number;
36
+ optional?: boolean;
37
+ };
38
+ export type UploadParameterDto = {
39
+ name?: string;
40
+ value?: string;
41
+ hidden?: boolean;
42
+ excluded?: boolean;
43
+ masked?: boolean;
44
+ };
45
+ export type UploadLinkDto = {
46
+ name?: string;
47
+ url?: string;
48
+ type?: string;
49
+ };
50
+ export type UploadLabelDto = {
51
+ name?: string;
52
+ value?: string;
53
+ };
54
+ export type UploadTestResultBodyStepDto = {
55
+ type: "body";
56
+ body?: string;
57
+ bodyJson?: unknown;
58
+ status?: UploadTestStatus;
59
+ start?: number;
60
+ stop?: number;
61
+ duration?: number;
62
+ message?: string;
63
+ trace?: string;
64
+ parameters?: UploadParameterDto[];
65
+ steps?: UploadTestResultStepDto[];
66
+ expectedResultSteps?: UploadTestResultStepDto[];
67
+ };
68
+ export type UploadTestResultExpectedBodyStepDto = {
69
+ type: "expected_body";
70
+ body?: string;
71
+ bodyJson?: unknown;
72
+ status?: UploadTestStatus;
73
+ start?: number;
74
+ stop?: number;
75
+ duration?: number;
76
+ message?: string;
77
+ };
78
+ export type UploadTestResultAttachmentStepDto = {
79
+ type: "attachment";
80
+ attachment?: UploadAttachmentDto;
81
+ status?: UploadTestStatus;
82
+ start?: number;
83
+ stop?: number;
84
+ duration?: number;
85
+ };
86
+ export type UploadTestResultUnknownStepDto = {
87
+ type?: string;
88
+ };
89
+ export type UploadTestResultStepDto = UploadTestResultBodyStepDto | UploadTestResultExpectedBodyStepDto | UploadTestResultAttachmentStepDto | UploadTestResultUnknownStepDto;
90
+ export type UploadTestResultDto = {
91
+ uuid?: string;
92
+ historyId?: string;
93
+ testCaseId?: string;
94
+ name?: string;
95
+ fullName?: string;
96
+ description?: string;
97
+ descriptionHtml?: string;
98
+ precondition?: string;
99
+ preconditionHtml?: string;
100
+ expectedResult?: string;
101
+ expectedResultHtml?: string;
102
+ start?: number;
103
+ stop?: number;
104
+ duration?: number;
105
+ status?: UploadTestStatus;
106
+ message?: string;
107
+ trace?: string;
108
+ hostId?: string;
109
+ threadId?: string;
110
+ environment?: string;
111
+ category?: UploadTestResultCategoryDto;
112
+ namedEnv?: UploadTestResultNamedEnvDto;
113
+ steps?: UploadTestResultStepDto[];
114
+ attachments?: UploadAttachmentDto[];
115
+ parameters?: UploadParameterDto[];
116
+ links?: UploadLinkDto[];
117
+ labels?: UploadLabelDto[];
118
+ };
119
+ export type UploadResultsDto = {
120
+ testSessionId: number;
121
+ results?: UploadTestResultDto[];
122
+ };
123
+ export type UploadTestResultResponseDto = {
124
+ id?: number;
125
+ uuid?: string;
126
+ };
127
+ export type UploadResultsResponseDto = {
128
+ results?: UploadTestResultResponseDto[];
129
+ };
130
+ export type UploadTestFixtureType = "BEFORE" | "AFTER";
131
+ export type UploadTestFixtureResultDto = {
132
+ type?: UploadTestFixtureType;
133
+ uuid?: string;
134
+ name?: string;
135
+ start?: number;
136
+ stop?: number;
137
+ duration?: number;
138
+ status?: UploadTestStatus;
139
+ message?: string;
140
+ trace?: string;
141
+ steps?: UploadTestResultStepDto[];
142
+ };
143
+ export type UploadFixturesResultsDto = {
144
+ fixtures?: UploadTestFixtureResultDto[];
145
+ };
16
146
  export type TestResultWithCategories = Pick<TestResult, "status" | "labels" | "error" | "flaky" | "duration" | "transition" | "environment"> & {
17
147
  categories?: {
18
148
  id?: string;
package/dist/plugin.js CHANGED
@@ -19,6 +19,7 @@ import { bold } from "yoctocolors";
19
19
  import { TestOpsClient } from "./client.js";
20
20
  import { Logger } from "./logger.js";
21
21
  import { toUploadCategory } from "./uploadCategory.js";
22
+ import { uploadFilenameForLink } from "./uploaderDto.js";
22
23
  import { attachmentsResolverFactory, fixturesResolverFactory, resolvePluginOptions, unwrapStepsAttachments, } from "./utils.js";
23
24
  const categoryDisplayName = (cat) => cat.name ?? cat.grouping?.[0]?.name ?? cat.grouping?.[0]?.value ?? cat.grouping?.[0]?.key ?? cat.externalId;
24
25
  export class TestOpsPlugin {
@@ -201,12 +202,12 @@ _TestOpsPlugin_logger = new WeakMap(), _TestOpsPlugin_ci = new WeakMap(), _TestO
201
202
  attachmentsResolver: async (attachmentLink) => {
202
203
  const content = await store.attachmentContentById(attachmentLink.id);
203
204
  const body = await content?.readContent(async (stream) => stream);
204
- const attachmentName = attachmentLink.name || attachmentLink.originalFileName;
205
- if (attachmentName === undefined || body === undefined) {
205
+ const filename = uploadFilenameForLink(attachmentLink);
206
+ if (filename === undefined || body === undefined) {
206
207
  return undefined;
207
208
  }
208
209
  return {
209
- originalFileName: attachmentName,
210
+ originalFileName: filename,
210
211
  contentType: attachmentLink.contentType ?? "application/octet-stream",
211
212
  content: body,
212
213
  };
@@ -0,0 +1,9 @@
1
+ import type { AttachmentLink } from "@allurereport/core-api";
2
+ import type { UploadAttachmentDto, UploadFixturesResultsDto, UploadResultsDto, UploadTestFixtureResultDto, UploadTestResultDto } from "./model.js";
3
+ import type { TestOpsFixtureResult, TestOpsPluginTestResult } from "./model.js";
4
+ export declare const uploadFilenameForLink: (link: AttachmentLink) => string | undefined;
5
+ export declare const toUploadAttachmentDto: (link: AttachmentLink) => UploadAttachmentDto;
6
+ export declare const toUploadTestResultDto: (tr: TestOpsPluginTestResult) => UploadTestResultDto;
7
+ export declare const toUploadResultsDto: (testSessionId: number, trs: TestOpsPluginTestResult[]) => UploadResultsDto;
8
+ export declare const toUploadFixtureResultDto: (fxt: TestOpsFixtureResult) => UploadTestFixtureResultDto;
9
+ export declare const toUploadFixturesResultsDto: (fixtures: TestOpsFixtureResult[]) => UploadFixturesResultsDto;
@@ -0,0 +1,132 @@
1
+ const isObject = (v) => typeof v === "object" && v !== null;
2
+ const hasString = (obj, key) => typeof obj[key] === "string";
3
+ export const uploadFilenameForLink = (link) => {
4
+ if ("originalFileName" in link && typeof link.originalFileName === "string")
5
+ return link.originalFileName;
6
+ return undefined;
7
+ };
8
+ export const toUploadAttachmentDto = (link) => {
9
+ return {
10
+ name: "name" in link && typeof link.name === "string" ? link.name : undefined,
11
+ originalFileName: uploadFilenameForLink(link),
12
+ contentType: "contentType" in link && typeof link.contentType === "string" ? link.contentType : undefined,
13
+ contentLength: "contentLength" in link && typeof link.contentLength === "number" ? link.contentLength : undefined,
14
+ optional: "optional" in link && typeof link.optional === "boolean"
15
+ ? link.optional
16
+ : undefined,
17
+ };
18
+ };
19
+ const toUploadStepDto = (step) => {
20
+ if (step.type === "attachment") {
21
+ return {
22
+ type: "attachment",
23
+ attachment: toUploadAttachmentDto(step.link),
24
+ };
25
+ }
26
+ return {
27
+ type: "body",
28
+ body: step.name,
29
+ status: step.status,
30
+ start: step.start,
31
+ stop: step.stop,
32
+ duration: step.duration,
33
+ message: typeof step.message === "string" ? step.message : undefined,
34
+ trace: typeof step.trace === "string" ? step.trace : undefined,
35
+ parameters: step.parameters,
36
+ steps: step.steps?.map(toUploadStepDto),
37
+ };
38
+ };
39
+ const normalizeCategory = (category) => {
40
+ if (!category)
41
+ return undefined;
42
+ const externalIdUnknown = category.externalId;
43
+ const groupingUnknown = category.grouping;
44
+ const externalId = typeof externalIdUnknown === "string"
45
+ ? externalIdUnknown
46
+ : typeof externalIdUnknown === "number"
47
+ ? String(externalIdUnknown)
48
+ : undefined;
49
+ if (!externalId)
50
+ return undefined;
51
+ const grouping = Array.isArray(groupingUnknown)
52
+ ? groupingUnknown
53
+ .filter(isObject)
54
+ .map((g) => ({
55
+ key: hasString(g, "key") ? g.key : undefined,
56
+ value: hasString(g, "value") ? g.value : undefined,
57
+ name: hasString(g, "name") ? g.name : undefined,
58
+ }))
59
+ .filter((g) => g.key || g.value || g.name)
60
+ : undefined;
61
+ return {
62
+ externalId,
63
+ ...(grouping && grouping.length > 0 ? { grouping } : {}),
64
+ };
65
+ };
66
+ const optionalArray = (v, isItem) => {
67
+ if (!Array.isArray(v))
68
+ return undefined;
69
+ const out = [];
70
+ for (const item of v) {
71
+ if (isItem(item))
72
+ out.push(item);
73
+ }
74
+ return out;
75
+ };
76
+ const isAttachmentLink = (v) => isObject(v) && hasString(v, "id");
77
+ export const toUploadTestResultDto = (tr) => {
78
+ const attachmentsUnknown = tr.attachments;
79
+ const attachments = optionalArray(attachmentsUnknown, isAttachmentLink)?.map(toUploadAttachmentDto);
80
+ return {
81
+ uuid: tr.id,
82
+ historyId: tr.historyId,
83
+ testCaseId: tr.testCase?.id,
84
+ name: tr.name,
85
+ fullName: tr.fullName,
86
+ description: tr.description,
87
+ descriptionHtml: tr.descriptionHtml,
88
+ precondition: tr.precondition,
89
+ preconditionHtml: tr.preconditionHtml,
90
+ expectedResult: tr.expectedResult,
91
+ expectedResultHtml: tr.expectedResultHtml,
92
+ start: tr.start,
93
+ stop: tr.stop,
94
+ duration: tr.duration,
95
+ status: tr.status,
96
+ message: tr.message,
97
+ trace: tr.trace,
98
+ hostId: tr.hostId,
99
+ threadId: tr.threadId,
100
+ environment: tr.environment,
101
+ ...(normalizeCategory(tr.category) ? { category: normalizeCategory(tr.category) } : {}),
102
+ ...(typeof tr.namedEnv?.id === "number" ? { namedEnv: { id: tr.namedEnv.id } } : {}),
103
+ steps: tr.steps?.map(toUploadStepDto),
104
+ ...(attachments ? { attachments } : {}),
105
+ parameters: tr.parameters,
106
+ links: tr.links,
107
+ labels: tr.labels,
108
+ };
109
+ };
110
+ export const toUploadResultsDto = (testSessionId, trs) => {
111
+ return {
112
+ testSessionId,
113
+ results: trs.map(toUploadTestResultDto),
114
+ };
115
+ };
116
+ export const toUploadFixtureResultDto = (fxt) => {
117
+ return {
118
+ type: fxt.type,
119
+ uuid: fxt.id,
120
+ name: fxt.name,
121
+ start: fxt.start,
122
+ stop: fxt.stop,
123
+ duration: fxt.duration,
124
+ status: fxt.status,
125
+ message: fxt.error?.message,
126
+ trace: fxt.error?.trace,
127
+ steps: fxt.steps?.map(toUploadStepDto),
128
+ };
129
+ };
130
+ export const toUploadFixturesResultsDto = (fixtures) => {
131
+ return { fixtures: fixtures.map(toUploadFixtureResultDto) };
132
+ };
package/dist/utils.js CHANGED
@@ -1,4 +1,5 @@
1
1
  import { env } from "node:process";
2
+ import { uploadFilenameForLink } from "./uploaderDto.js";
2
3
  export const unwrapStepsAttachments = (steps) => {
3
4
  return steps.map((step) => {
4
5
  if (step.type === "attachment") {
@@ -40,12 +41,12 @@ export function attachmentsResolverFactory(store) {
40
41
  await Promise.all(attachments.map(async (attachment) => {
41
42
  const content = await store.attachmentContentById(attachment.id);
42
43
  const body = await content?.readContent(async (s) => s);
43
- const name = attachment.name || attachment.originalFileName;
44
- if (name === undefined || body === undefined) {
44
+ const filename = uploadFilenameForLink(attachment);
45
+ if (filename === undefined || body === undefined) {
45
46
  return undefined;
46
47
  }
47
48
  result.push({
48
- originalFileName: name,
49
+ originalFileName: filename,
49
50
  contentType: attachment.contentType ?? "application/octet-stream",
50
51
  content: body,
51
52
  });
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@allurereport/plugin-testops",
3
- "version": "3.6.1",
3
+ "version": "3.6.2",
4
4
  "description": "Allure Plugin TestOps",
5
5
  "keywords": [
6
6
  "allure",
@@ -32,10 +32,10 @@
32
32
  "lint:fix": "oxlint --import-plugin --fix src test features stories"
33
33
  },
34
34
  "dependencies": {
35
- "@allurereport/ci": "3.6.1",
36
- "@allurereport/core-api": "3.6.1",
37
- "@allurereport/plugin-api": "3.6.1",
38
- "@allurereport/reader-api": "3.6.1",
35
+ "@allurereport/ci": "3.6.2",
36
+ "@allurereport/core-api": "3.6.2",
37
+ "@allurereport/plugin-api": "3.6.2",
38
+ "@allurereport/reader-api": "3.6.2",
39
39
  "axios": "^1.15.0",
40
40
  "form-data": "^4.0.5",
41
41
  "lodash-es": "^4.18.1",