@allurereport/reader 3.0.0-beta.7 → 3.0.0-beta.9

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.
@@ -18,7 +18,7 @@ const xmlParser = new XMLParser({
18
18
  const readerId = "allure2";
19
19
  export const allure2 = {
20
20
  read: async (visitor, data) => {
21
- if (data.getOriginalFileName().match(/.*-attachment(\..+)?/)) {
21
+ if (data.getOriginalFileName().match(/-attachment(?:\..+)?/)) {
22
22
  await visitor.visitAttachmentFile(data, { readerId });
23
23
  return true;
24
24
  }
@@ -1,7 +1,17 @@
1
+ import { BufferResultFile } from "@allurereport/reader-api";
1
2
  import { XMLParser } from "fast-xml-parser";
2
3
  import * as console from "node:console";
4
+ import { randomUUID } from "node:crypto";
3
5
  import { ensureString } from "../utils.js";
4
6
  import { isEmptyElement, isStringAnyRecord, isStringAnyRecordArray } from "../xml-utils.js";
7
+ const MS_IN_S = 1000;
8
+ const DEFAULT_TEST_NAME = "The test's name is not defined";
9
+ const STDOUT_ATTACHMENT_NAME = "System output";
10
+ const STDERR_ATTACHMENT_NAME = "System error";
11
+ const SUITE_PACKAGE_NAME = "package";
12
+ const SUITE_PARENT_LABEL_NAME = "parentSuite";
13
+ const SUITE_LABEL_NAME = "suite";
14
+ const TEST_CLASS_LABEL_NAME = "testClass";
5
15
  const arrayTags = new Set(["testsuite.testcase", "testsuites.testsuite", "testsuites.testsuite.testcase"]);
6
16
  const xmlParser = new XMLParser({
7
17
  parseTagValue: false,
@@ -56,49 +66,93 @@ const parseRootElement = async (visitor, xml) => {
56
66
  return false;
57
67
  }
58
68
  for (const testSuitesArrayElement of testSuitesArray) {
59
- await parseTestSuite(visitor, testSuitesArrayElement);
69
+ await parseTestSuite(visitor, testSuitesArrayElement, true);
60
70
  }
61
71
  return true;
62
72
  }
63
73
  if (!isStringAnyRecord(testSuite)) {
64
74
  return false;
65
75
  }
66
- await parseTestSuite(visitor, testSuite);
76
+ await parseTestSuite(visitor, testSuite, false);
67
77
  return true;
68
78
  };
69
- const parseTestSuite = async (visitor, testSuite) => {
70
- const { name, testcase } = testSuite;
79
+ const parseTestSuite = async (visitor, testSuite, isAggregated) => {
80
+ const { name, package: packageAttribute, testcase } = testSuite;
71
81
  if (!isStringAnyRecordArray(testcase)) {
72
82
  return;
73
83
  }
74
84
  for (const testcaseElement of testcase) {
75
- await parseTestCase(visitor, { name: ensureString(name) }, testcaseElement);
85
+ await parseTestCase(visitor, { name: ensureString(name), suitePackage: ensureString(packageAttribute) }, testcaseElement, isAggregated);
76
86
  }
77
87
  };
78
- const parseTestCase = async (visitor, suite, testCase) => {
79
- const { name, failure, skipped } = testCase;
80
- const { status, message, trace } = getStatus(failure, skipped);
88
+ const parseTestCase = async (visitor, { name: suiteName, suitePackage }, testCase, isAggregated) => {
89
+ const { "name": nameAttribute, failure, error, skipped, "classname": classNameAttribute, time, "system-out": systemOutAttribute, "system-err": systemErrAttribute, } = testCase;
90
+ const name = ensureString(nameAttribute);
91
+ const className = ensureString(classNameAttribute);
92
+ const systemOut = ensureString(systemOutAttribute);
93
+ const systemErr = ensureString(systemErrAttribute);
94
+ const { status, message, trace } = getStatus(failure, error, skipped);
81
95
  await visitor.visitTestResult({
82
- name: ensureString(name),
96
+ name: name ?? DEFAULT_TEST_NAME,
97
+ fullName: convertFullName(className, name),
98
+ duration: convertDuration(time),
83
99
  status,
84
100
  message,
85
101
  trace,
102
+ steps: await parseAttachments(visitor, systemOut, systemErr),
103
+ labels: convertLabels({ suitePackage, suiteName, className, isAggregated }),
86
104
  }, { readerId });
87
105
  };
88
- const getStatus = (failure, skipped) => {
89
- if (isEmptyElement(failure)) {
90
- return { status: "failed" };
106
+ const convertFullName = (className, name) => (className && name ? `${className}.${name}` : undefined);
107
+ const parseAttachments = async (visitor, systemOut, systemErr) => {
108
+ const attachments = [];
109
+ if (systemOut) {
110
+ attachments.push(await visitPlainTextAttachment(visitor, STDOUT_ATTACHMENT_NAME, systemOut));
91
111
  }
92
- if (isStringAnyRecord(failure)) {
93
- const { message, "#text": trace } = failure;
94
- return { status: "failed", message: ensureString(message), trace: ensureString(trace) };
112
+ if (systemErr) {
113
+ attachments.push(await visitPlainTextAttachment(visitor, STDERR_ATTACHMENT_NAME, systemErr));
95
114
  }
96
- if (isEmptyElement(skipped)) {
97
- return { status: "skipped" };
115
+ return attachments;
116
+ };
117
+ const visitPlainTextAttachment = async (visitor, name, content) => {
118
+ const fileName = randomUUID();
119
+ await visitor.visitAttachmentFile(new BufferResultFile(Buffer.from(content), fileName), { readerId });
120
+ return {
121
+ type: "attachment",
122
+ contentType: "text/plain",
123
+ originalFileName: fileName,
124
+ name,
125
+ };
126
+ };
127
+ const convertLabels = ({ suitePackage, suiteName, className, isAggregated, }) => {
128
+ const labels = [];
129
+ if (suitePackage) {
130
+ labels.push({ name: SUITE_PACKAGE_NAME, value: suitePackage });
131
+ if (isAggregated) {
132
+ labels.push({ name: SUITE_PARENT_LABEL_NAME, value: suitePackage });
133
+ }
134
+ }
135
+ if (suiteName) {
136
+ labels.push({ name: SUITE_LABEL_NAME, value: suiteName });
137
+ }
138
+ if (className) {
139
+ labels.push({ name: TEST_CLASS_LABEL_NAME, value: className });
140
+ }
141
+ return labels;
142
+ };
143
+ const convertDuration = (timeAttribute) => {
144
+ const time = ensureString(timeAttribute);
145
+ return time ? Math.round(parseFloat(time) * MS_IN_S) : undefined;
146
+ };
147
+ const getStatus = (failure, error, skipped) => maybeParseStatus("failed", failure) ??
148
+ maybeParseStatus("broken", error) ??
149
+ maybeParseStatus("skipped", skipped) ?? { status: "passed" };
150
+ const maybeParseStatus = (status, element) => {
151
+ if (isEmptyElement(element)) {
152
+ return { status };
98
153
  }
99
- if (isStringAnyRecord(skipped)) {
100
- const { message, "#text": trace } = skipped;
101
- return { status: "skipped", message: ensureString(message), trace: ensureString(trace) };
154
+ if (isStringAnyRecord(element)) {
155
+ const { message, "#text": trace } = element;
156
+ return { status, message: ensureString(message), trace: ensureString(trace) };
102
157
  }
103
- return { status: "passed" };
104
158
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@allurereport/reader",
3
- "version": "3.0.0-beta.7",
3
+ "version": "3.0.0-beta.9",
4
4
  "description": "Collection of utilities which helps to process different kind of test results as Allure Results",
5
5
  "keywords": [
6
6
  "allure",
@@ -26,9 +26,9 @@
26
26
  "test": "vitest run"
27
27
  },
28
28
  "dependencies": {
29
- "@allurereport/core-api": "3.0.0-beta.7",
30
- "@allurereport/plugin-api": "3.0.0-beta.7",
31
- "@allurereport/reader-api": "3.0.0-beta.7",
29
+ "@allurereport/core-api": "3.0.0-beta.9",
30
+ "@allurereport/plugin-api": "3.0.0-beta.9",
31
+ "@allurereport/reader-api": "3.0.0-beta.9",
32
32
  "fast-xml-parser": "^4.5.0"
33
33
  },
34
34
  "devDependencies": {
@@ -38,8 +38,8 @@
38
38
  "@typescript-eslint/eslint-plugin": "^8.0.0",
39
39
  "@typescript-eslint/parser": "^8.0.0",
40
40
  "@vitest/runner": "^2.1.8",
41
- "allure-js-commons": "^3.0.7",
42
- "allure-vitest": "^3.0.7",
41
+ "allure-js-commons": "^3.0.9",
42
+ "allure-vitest": "^3.0.9",
43
43
  "eslint": "^8.57.0",
44
44
  "eslint-config-prettier": "^9.1.0",
45
45
  "eslint-plugin-import": "^2.29.1",