cucumberjs-qase-reporter 2.2.2 → 2.4.0
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/changelog.md +21 -0
- package/dist/models.d.ts +1 -0
- package/dist/modules/eventStorage.d.ts +27 -0
- package/dist/modules/eventStorage.js +114 -0
- package/dist/modules/profilerTracker.d.ts +11 -0
- package/dist/modules/profilerTracker.js +28 -0
- package/dist/modules/resultBuilder.d.ts +22 -0
- package/dist/modules/resultBuilder.js +63 -0
- package/dist/modules/statusMaps.d.ts +5 -0
- package/dist/modules/statusMaps.js +23 -0
- package/dist/modules/statusTracker.d.ts +10 -0
- package/dist/modules/statusTracker.js +51 -0
- package/dist/modules/stepConverter.d.ts +6 -0
- package/dist/modules/stepConverter.js +38 -0
- package/dist/modules/tagParser.d.ts +6 -0
- package/dist/modules/tagParser.js +99 -0
- package/dist/reporter.d.ts +0 -5
- package/dist/reporter.js +5 -9
- package/dist/storage.d.ts +7 -116
- package/dist/storage.js +57 -455
- package/docs/usage.md +27 -0
- package/package.json +2 -2
package/changelog.md
CHANGED
|
@@ -1,3 +1,24 @@
|
|
|
1
|
+
# cucumberjs-qase-reporter@2.4.0
|
|
2
|
+
|
|
3
|
+
## Changed
|
|
4
|
+
|
|
5
|
+
- Decomposed `storage.ts` (595 LOC) into a thin facade plus 6 focused modules under `src/modules/`: `TagParser`, `EventStorage`, `StatusTracker`, `StepConverter`, `ProfilerTracker`, `ResultBuilder`, plus `STATUS_MAP` / `STEP_STATUS_MAP` constants. Public contract preserved: `Storage` named export, constructor signature, all 7 instance methods, static `statusMap` and `stepStatusMap`, all 9 user-facing tag patterns.
|
|
6
|
+
|
|
7
|
+
## Bug fixes
|
|
8
|
+
|
|
9
|
+
- Cross-reporter consistency: `testops_id` is now `null` when project mapping (`@qaseid.PROJ(ids)` tag) is set, matching the behavior of mocha / cypress / jest reporters. Previously cucumberjs emitted both `testops_id: ids` and `testops_project_mapping: mapping`, which could lead to ambiguous results in multi-project runs.
|
|
10
|
+
|
|
11
|
+
## Internal
|
|
12
|
+
|
|
13
|
+
- Added 38 per-module unit tests on top of the existing 44 facade integration tests (82 total).
|
|
14
|
+
|
|
15
|
+
# cucumberjs-qase-reporter@2.3.0
|
|
16
|
+
|
|
17
|
+
## What's new
|
|
18
|
+
|
|
19
|
+
- Added `@QaseTags=tag1,tag2` Gherkin tag to assign tags from feature files.
|
|
20
|
+
- Updated `qase-javascript-commons` dependency to `~2.6.0`.
|
|
21
|
+
|
|
1
22
|
# cucumberjs-qase-reporter@2.2.2
|
|
2
23
|
|
|
3
24
|
## Bug fixes
|
package/dist/models.d.ts
CHANGED
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { Attachment as Attach, GherkinDocument, Pickle, TestCaseStarted, TestStepFinished } from '@cucumber/messages';
|
|
2
|
+
import { TestCase } from '@cucumber/messages/dist/esm/src/messages';
|
|
3
|
+
import { Attachment } from 'qase-javascript-commons';
|
|
4
|
+
import { ScenarioData } from '../models';
|
|
5
|
+
export declare class EventStorage {
|
|
6
|
+
private pickles;
|
|
7
|
+
private testCaseStarts;
|
|
8
|
+
private testStepFinished;
|
|
9
|
+
private testCases;
|
|
10
|
+
private scenarios;
|
|
11
|
+
private attachments;
|
|
12
|
+
addPickle(pickle: Pickle): void;
|
|
13
|
+
addScenario(document: GherkinDocument): void;
|
|
14
|
+
addAttachment(attachment: Attach): void;
|
|
15
|
+
addTestCase(testCase: TestCase): void;
|
|
16
|
+
addTestCaseStarted(testCaseStarted: TestCaseStarted): void;
|
|
17
|
+
addTestStepFinished(step: TestStepFinished): void;
|
|
18
|
+
getPickle(id: string): Pickle | undefined;
|
|
19
|
+
getTestCase(id: string): TestCase | undefined;
|
|
20
|
+
getTestCaseStarted(id: string): TestCaseStarted | undefined;
|
|
21
|
+
getScenario(id: string): ScenarioData | undefined;
|
|
22
|
+
getAttachments(key: string): Attachment[];
|
|
23
|
+
getTestStepFinished(id: string): TestStepFinished | undefined;
|
|
24
|
+
getAllTestStepFinished(): Map<string, TestStepFinished>;
|
|
25
|
+
private appendAttachment;
|
|
26
|
+
static getFileNameFromMediaType(mediaType: string): string;
|
|
27
|
+
}
|
|
@@ -0,0 +1,114 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.EventStorage = void 0;
|
|
4
|
+
const uuid_1 = require("uuid");
|
|
5
|
+
class EventStorage {
|
|
6
|
+
pickles = {};
|
|
7
|
+
testCaseStarts = {};
|
|
8
|
+
testStepFinished = {};
|
|
9
|
+
testCases = {};
|
|
10
|
+
scenarios = {};
|
|
11
|
+
attachments = {};
|
|
12
|
+
addPickle(pickle) {
|
|
13
|
+
this.pickles[pickle.id] = pickle;
|
|
14
|
+
}
|
|
15
|
+
addScenario(document) {
|
|
16
|
+
if (!document.feature)
|
|
17
|
+
return;
|
|
18
|
+
const { children, name } = document.feature;
|
|
19
|
+
for (const { scenario } of children) {
|
|
20
|
+
if (!scenario)
|
|
21
|
+
continue;
|
|
22
|
+
const parameters = {};
|
|
23
|
+
scenario.examples?.forEach((example) => {
|
|
24
|
+
if (example.tableHeader) {
|
|
25
|
+
const columnNames = example.tableHeader.cells.map((cell) => cell.value);
|
|
26
|
+
example.tableBody.forEach((row) => {
|
|
27
|
+
const rowParams = {};
|
|
28
|
+
row.cells.forEach((cell, index) => {
|
|
29
|
+
const columnName = columnNames[index];
|
|
30
|
+
if (columnName) {
|
|
31
|
+
rowParams[columnName] = cell.value;
|
|
32
|
+
}
|
|
33
|
+
});
|
|
34
|
+
parameters[row.id] = rowParams;
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
});
|
|
38
|
+
this.scenarios[scenario.id] = {
|
|
39
|
+
name,
|
|
40
|
+
parameters,
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
addAttachment(attachment) {
|
|
45
|
+
if (attachment.testStepId) {
|
|
46
|
+
this.appendAttachment(attachment.testStepId, attachment);
|
|
47
|
+
}
|
|
48
|
+
if (attachment.testCaseStartedId) {
|
|
49
|
+
this.appendAttachment(attachment.testCaseStartedId, attachment);
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
addTestCase(testCase) {
|
|
53
|
+
this.testCases[testCase.id] = testCase;
|
|
54
|
+
}
|
|
55
|
+
addTestCaseStarted(testCaseStarted) {
|
|
56
|
+
this.testCaseStarts[testCaseStarted.id] = testCaseStarted;
|
|
57
|
+
}
|
|
58
|
+
addTestStepFinished(step) {
|
|
59
|
+
this.testStepFinished[step.testStepId] = step;
|
|
60
|
+
}
|
|
61
|
+
getPickle(id) {
|
|
62
|
+
return this.pickles[id];
|
|
63
|
+
}
|
|
64
|
+
getTestCase(id) {
|
|
65
|
+
return this.testCases[id];
|
|
66
|
+
}
|
|
67
|
+
getTestCaseStarted(id) {
|
|
68
|
+
return this.testCaseStarts[id];
|
|
69
|
+
}
|
|
70
|
+
getScenario(id) {
|
|
71
|
+
return this.scenarios[id];
|
|
72
|
+
}
|
|
73
|
+
getAttachments(key) {
|
|
74
|
+
return this.attachments[key] ?? [];
|
|
75
|
+
}
|
|
76
|
+
getTestStepFinished(id) {
|
|
77
|
+
return this.testStepFinished[id];
|
|
78
|
+
}
|
|
79
|
+
getAllTestStepFinished() {
|
|
80
|
+
return new Map(Object.entries(this.testStepFinished));
|
|
81
|
+
}
|
|
82
|
+
appendAttachment(key, attachment) {
|
|
83
|
+
const list = this.attachments[key] ?? [];
|
|
84
|
+
this.attachments[key] = list;
|
|
85
|
+
list.push({
|
|
86
|
+
file_name: EventStorage.getFileNameFromMediaType(attachment.mediaType),
|
|
87
|
+
mime_type: attachment.mediaType,
|
|
88
|
+
file_path: null,
|
|
89
|
+
content: attachment.body,
|
|
90
|
+
size: 0,
|
|
91
|
+
id: (0, uuid_1.v4)(),
|
|
92
|
+
});
|
|
93
|
+
}
|
|
94
|
+
static getFileNameFromMediaType(mediaType) {
|
|
95
|
+
const extensions = {
|
|
96
|
+
'text/plain': 'txt',
|
|
97
|
+
'application/json': 'json',
|
|
98
|
+
'image/png': 'png',
|
|
99
|
+
'image/jpeg': 'jpg',
|
|
100
|
+
'image/gif': 'gif',
|
|
101
|
+
'text/html': 'html',
|
|
102
|
+
'application/pdf': 'pdf',
|
|
103
|
+
'application/xml': 'xml',
|
|
104
|
+
'application/zip': 'zip',
|
|
105
|
+
'application/msword': 'doc',
|
|
106
|
+
'application/vnd.ms-excel': 'xls',
|
|
107
|
+
'application/vnd.openxmlformats-officedocument.wordprocessingml.document': 'docx',
|
|
108
|
+
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet': 'xlsx',
|
|
109
|
+
};
|
|
110
|
+
const extension = extensions[mediaType];
|
|
111
|
+
return extension ? `file.${extension}` : 'file';
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
exports.EventStorage = EventStorage;
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { TestStepType } from 'qase-javascript-commons';
|
|
2
|
+
import { NetworkProfiler } from 'qase-javascript-commons/profilers';
|
|
3
|
+
export declare class ProfilerTracker {
|
|
4
|
+
private readonly profiler;
|
|
5
|
+
private snapshots;
|
|
6
|
+
constructor(profiler: NetworkProfiler | null);
|
|
7
|
+
onTestStart(testCaseStartedId: string): void;
|
|
8
|
+
getEvents(testCaseStartedId: string): TestStepType[];
|
|
9
|
+
reset(testCaseStartedId: string): void;
|
|
10
|
+
restore(): void;
|
|
11
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ProfilerTracker = void 0;
|
|
4
|
+
class ProfilerTracker {
|
|
5
|
+
profiler;
|
|
6
|
+
snapshots = {};
|
|
7
|
+
constructor(profiler) {
|
|
8
|
+
this.profiler = profiler;
|
|
9
|
+
}
|
|
10
|
+
onTestStart(testCaseStartedId) {
|
|
11
|
+
if (this.profiler) {
|
|
12
|
+
this.snapshots[testCaseStartedId] = this.profiler.getAllSteps().length;
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
getEvents(testCaseStartedId) {
|
|
16
|
+
if (!this.profiler)
|
|
17
|
+
return [];
|
|
18
|
+
const snapshot = this.snapshots[testCaseStartedId] ?? 0;
|
|
19
|
+
return this.profiler.getAllSteps().slice(snapshot);
|
|
20
|
+
}
|
|
21
|
+
reset(testCaseStartedId) {
|
|
22
|
+
delete this.snapshots[testCaseStartedId];
|
|
23
|
+
}
|
|
24
|
+
restore() {
|
|
25
|
+
this.profiler?.restore();
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
exports.ProfilerTracker = ProfilerTracker;
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { Pickle, TestCaseFinished, TestCaseStarted } from '@cucumber/messages';
|
|
2
|
+
import { TestCase } from '@cucumber/messages/dist/esm/src/messages';
|
|
3
|
+
import { Attachment, CompoundError, TestResultType, TestStatusEnum, TestStepType } from 'qase-javascript-commons';
|
|
4
|
+
import { TestMetadata } from '../models';
|
|
5
|
+
export interface BuildArgs {
|
|
6
|
+
testCaseFinished: TestCaseFinished;
|
|
7
|
+
testCaseStarted: TestCaseStarted;
|
|
8
|
+
testCase: TestCase;
|
|
9
|
+
pickle: Pickle;
|
|
10
|
+
metadata: TestMetadata;
|
|
11
|
+
status: TestStatusEnum;
|
|
12
|
+
error: CompoundError | undefined;
|
|
13
|
+
steps: TestStepType[];
|
|
14
|
+
profilerSteps: TestStepType[];
|
|
15
|
+
attachments: Attachment[];
|
|
16
|
+
scenarioName: string | undefined;
|
|
17
|
+
scenarioParameters: Record<string, string>;
|
|
18
|
+
}
|
|
19
|
+
export declare class ResultBuilder {
|
|
20
|
+
static build(args: BuildArgs): TestResultType;
|
|
21
|
+
static getSignature(pickle: Pickle, ids: number[], parameters?: Record<string, string>): string;
|
|
22
|
+
}
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ResultBuilder = void 0;
|
|
4
|
+
const qase_javascript_commons_1 = require("qase-javascript-commons");
|
|
5
|
+
class ResultBuilder {
|
|
6
|
+
static build(args) {
|
|
7
|
+
const { testCaseFinished, testCaseStarted, pickle, metadata, status, error, steps, profilerSteps, attachments, scenarioName, scenarioParameters, } = args;
|
|
8
|
+
let relations = null;
|
|
9
|
+
if (metadata.suite) {
|
|
10
|
+
const suiteParts = metadata.suite.split('\t').filter((part) => part.trim().length > 0);
|
|
11
|
+
relations = {
|
|
12
|
+
suite: {
|
|
13
|
+
data: suiteParts.map((suite) => ({
|
|
14
|
+
title: suite.trim(),
|
|
15
|
+
public_id: null,
|
|
16
|
+
})),
|
|
17
|
+
},
|
|
18
|
+
};
|
|
19
|
+
}
|
|
20
|
+
else if (scenarioName !== undefined) {
|
|
21
|
+
relations = {
|
|
22
|
+
suite: {
|
|
23
|
+
data: [
|
|
24
|
+
{ title: scenarioName, public_id: null },
|
|
25
|
+
],
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
}
|
|
29
|
+
// Merge scenario params with metadata parameters (metadata wins)
|
|
30
|
+
const params = { ...scenarioParameters, ...metadata.parameters };
|
|
31
|
+
const hasProjectMapping = Object.keys(metadata.projectMapping).length > 0;
|
|
32
|
+
return {
|
|
33
|
+
attachments,
|
|
34
|
+
author: null,
|
|
35
|
+
execution: {
|
|
36
|
+
status,
|
|
37
|
+
start_time: testCaseStarted.timestamp.seconds,
|
|
38
|
+
end_time: testCaseFinished.timestamp.seconds,
|
|
39
|
+
duration: Math.abs(testCaseFinished.timestamp.seconds - testCaseStarted.timestamp.seconds) * 1000,
|
|
40
|
+
stacktrace: error?.stacktrace ?? null,
|
|
41
|
+
thread: null,
|
|
42
|
+
},
|
|
43
|
+
fields: metadata.fields,
|
|
44
|
+
message: error?.message ?? null,
|
|
45
|
+
muted: false,
|
|
46
|
+
params,
|
|
47
|
+
group_params: metadata.group_params,
|
|
48
|
+
relations,
|
|
49
|
+
run_id: null,
|
|
50
|
+
signature: ResultBuilder.getSignature(pickle, metadata.ids, params),
|
|
51
|
+
steps: [...steps, ...profilerSteps],
|
|
52
|
+
testops_id: hasProjectMapping ? null : (metadata.ids.length > 0 ? metadata.ids : null),
|
|
53
|
+
testops_project_mapping: hasProjectMapping ? metadata.projectMapping : null,
|
|
54
|
+
id: testCaseStarted.id,
|
|
55
|
+
title: metadata.title ?? pickle.name,
|
|
56
|
+
tags: metadata.tags,
|
|
57
|
+
};
|
|
58
|
+
}
|
|
59
|
+
static getSignature(pickle, ids, parameters = {}) {
|
|
60
|
+
return (0, qase_javascript_commons_1.generateSignature)(ids, [...pickle.uri.split('/'), pickle.name], parameters);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
exports.ResultBuilder = ResultBuilder;
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { Status } from '@cucumber/cucumber';
|
|
2
|
+
import { StepStatusEnum, TestStatusEnum } from 'qase-javascript-commons';
|
|
3
|
+
export type TestStepResultStatus = (typeof Status)[keyof typeof Status];
|
|
4
|
+
export declare const STATUS_MAP: Record<TestStepResultStatus, TestStatusEnum>;
|
|
5
|
+
export declare const STEP_STATUS_MAP: Record<TestStepResultStatus, StepStatusEnum>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.STEP_STATUS_MAP = exports.STATUS_MAP = void 0;
|
|
4
|
+
const cucumber_1 = require("@cucumber/cucumber");
|
|
5
|
+
const qase_javascript_commons_1 = require("qase-javascript-commons");
|
|
6
|
+
exports.STATUS_MAP = {
|
|
7
|
+
[cucumber_1.Status.PASSED]: qase_javascript_commons_1.TestStatusEnum.passed,
|
|
8
|
+
[cucumber_1.Status.FAILED]: qase_javascript_commons_1.TestStatusEnum.failed,
|
|
9
|
+
[cucumber_1.Status.SKIPPED]: qase_javascript_commons_1.TestStatusEnum.skipped,
|
|
10
|
+
[cucumber_1.Status.AMBIGUOUS]: qase_javascript_commons_1.TestStatusEnum.invalid,
|
|
11
|
+
[cucumber_1.Status.PENDING]: qase_javascript_commons_1.TestStatusEnum.skipped,
|
|
12
|
+
[cucumber_1.Status.UNDEFINED]: qase_javascript_commons_1.TestStatusEnum.skipped,
|
|
13
|
+
[cucumber_1.Status.UNKNOWN]: qase_javascript_commons_1.TestStatusEnum.skipped,
|
|
14
|
+
};
|
|
15
|
+
exports.STEP_STATUS_MAP = {
|
|
16
|
+
[cucumber_1.Status.PASSED]: qase_javascript_commons_1.StepStatusEnum.passed,
|
|
17
|
+
[cucumber_1.Status.FAILED]: qase_javascript_commons_1.StepStatusEnum.failed,
|
|
18
|
+
[cucumber_1.Status.SKIPPED]: qase_javascript_commons_1.StepStatusEnum.skipped,
|
|
19
|
+
[cucumber_1.Status.AMBIGUOUS]: qase_javascript_commons_1.StepStatusEnum.failed,
|
|
20
|
+
[cucumber_1.Status.PENDING]: qase_javascript_commons_1.StepStatusEnum.skipped,
|
|
21
|
+
[cucumber_1.Status.UNDEFINED]: qase_javascript_commons_1.StepStatusEnum.skipped,
|
|
22
|
+
[cucumber_1.Status.UNKNOWN]: qase_javascript_commons_1.StepStatusEnum.skipped,
|
|
23
|
+
};
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { TestStepFinished } from '@cucumber/messages';
|
|
2
|
+
import { CompoundError, TestStatusEnum } from 'qase-javascript-commons';
|
|
3
|
+
export declare class StatusTracker {
|
|
4
|
+
private results;
|
|
5
|
+
private errors;
|
|
6
|
+
onTestStarted(testCaseStartedId: string): void;
|
|
7
|
+
applyStep(step: TestStepFinished): void;
|
|
8
|
+
getStatus(testCaseStartedId: string): TestStatusEnum;
|
|
9
|
+
getErrors(testCaseStartedId: string): CompoundError | undefined;
|
|
10
|
+
}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StatusTracker = void 0;
|
|
4
|
+
const qase_javascript_commons_1 = require("qase-javascript-commons");
|
|
5
|
+
const statusMaps_1 = require("./statusMaps");
|
|
6
|
+
class StatusTracker {
|
|
7
|
+
results = {};
|
|
8
|
+
errors = {};
|
|
9
|
+
onTestStarted(testCaseStartedId) {
|
|
10
|
+
this.results[testCaseStartedId] = qase_javascript_commons_1.TestStatusEnum.passed;
|
|
11
|
+
}
|
|
12
|
+
applyStep(step) {
|
|
13
|
+
const oldStatus = this.results[step.testCaseStartedId];
|
|
14
|
+
let error = null;
|
|
15
|
+
if (step.testStepResult.message) {
|
|
16
|
+
error = new Error(step.testStepResult.message);
|
|
17
|
+
}
|
|
18
|
+
const newStatus = (0, qase_javascript_commons_1.determineTestStatus)(error, statusMaps_1.STATUS_MAP[step.testStepResult.status]);
|
|
19
|
+
if (newStatus !== qase_javascript_commons_1.TestStatusEnum.passed) {
|
|
20
|
+
if (step.testStepResult.message) {
|
|
21
|
+
if (!this.errors[step.testCaseStartedId]) {
|
|
22
|
+
this.errors[step.testCaseStartedId] = [];
|
|
23
|
+
}
|
|
24
|
+
this.errors[step.testCaseStartedId]?.push(step.testStepResult.message);
|
|
25
|
+
}
|
|
26
|
+
if (oldStatus) {
|
|
27
|
+
if (oldStatus !== qase_javascript_commons_1.TestStatusEnum.failed && oldStatus !== qase_javascript_commons_1.TestStatusEnum.invalid) {
|
|
28
|
+
this.results[step.testCaseStartedId] = newStatus;
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
else {
|
|
32
|
+
this.results[step.testCaseStartedId] = newStatus;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
getStatus(testCaseStartedId) {
|
|
37
|
+
return this.results[testCaseStartedId] ?? qase_javascript_commons_1.TestStatusEnum.passed;
|
|
38
|
+
}
|
|
39
|
+
getErrors(testCaseStartedId) {
|
|
40
|
+
const messages = this.errors[testCaseStartedId];
|
|
41
|
+
if (!messages)
|
|
42
|
+
return undefined;
|
|
43
|
+
const err = new qase_javascript_commons_1.CompoundError();
|
|
44
|
+
messages.forEach((message) => {
|
|
45
|
+
err.addMessage(message);
|
|
46
|
+
err.addStacktrace(message);
|
|
47
|
+
});
|
|
48
|
+
return err;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
exports.StatusTracker = StatusTracker;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import { PickleStep, TestStepFinished } from '@cucumber/messages';
|
|
2
|
+
import { TestCase } from '@cucumber/messages/dist/esm/src/messages';
|
|
3
|
+
import { Attachment, TestStepType } from 'qase-javascript-commons';
|
|
4
|
+
export declare class StepConverter {
|
|
5
|
+
static convert(pickleSteps: readonly PickleStep[], testCase: TestCase, finishedSteps: Map<string, TestStepFinished>, getAttachments: (stepId: string) => Attachment[]): TestStepType[];
|
|
6
|
+
}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.StepConverter = void 0;
|
|
4
|
+
const qase_javascript_commons_1 = require("qase-javascript-commons");
|
|
5
|
+
const statusMaps_1 = require("./statusMaps");
|
|
6
|
+
class StepConverter {
|
|
7
|
+
static convert(pickleSteps, testCase, finishedSteps, getAttachments) {
|
|
8
|
+
const results = [];
|
|
9
|
+
for (const s of testCase.testSteps) {
|
|
10
|
+
const finished = finishedSteps.get(s.id);
|
|
11
|
+
if (!finished)
|
|
12
|
+
continue;
|
|
13
|
+
const step = pickleSteps.find((ps) => ps.id === s.pickleStepId);
|
|
14
|
+
if (!step)
|
|
15
|
+
continue;
|
|
16
|
+
results.push({
|
|
17
|
+
id: s.id,
|
|
18
|
+
step_type: qase_javascript_commons_1.StepType.GHERKIN,
|
|
19
|
+
data: {
|
|
20
|
+
keyword: step.text,
|
|
21
|
+
name: step.text,
|
|
22
|
+
line: 0,
|
|
23
|
+
},
|
|
24
|
+
execution: {
|
|
25
|
+
status: statusMaps_1.STEP_STATUS_MAP[finished.testStepResult.status],
|
|
26
|
+
start_time: null,
|
|
27
|
+
end_time: null,
|
|
28
|
+
duration: finished.testStepResult.duration.seconds * 1000,
|
|
29
|
+
},
|
|
30
|
+
attachments: getAttachments(s.id),
|
|
31
|
+
steps: [],
|
|
32
|
+
parent_id: null,
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
return results;
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
exports.StepConverter = StepConverter;
|
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.TagParser = void 0;
|
|
4
|
+
const qase_javascript_commons_1 = require("qase-javascript-commons");
|
|
5
|
+
const qaseIdRegExp = /^@[Qq]-?(\d+)$/;
|
|
6
|
+
const newQaseIdRegExp = /^@[Qq]ase[Ii][Dd]=(\d+(?:,\s*\d+)*)$/;
|
|
7
|
+
const qaseTitleRegExp = /^@[Qq]ase[Tt]itle=(.+)$/;
|
|
8
|
+
const qaseFieldsRegExp = /^@[Qq]ase[Ff]ields=(.+)$/;
|
|
9
|
+
const qaseParametersRegExp = /^@[Qq]ase[Pp]arameters=(.+)$/;
|
|
10
|
+
const qaseGroupParametersRegExp = /^@[Qq]ase[Gg]roup[Pp]arameters=(.+)$/;
|
|
11
|
+
const qaseSuiteRegExp = /^@[Qq]ase[Ss]uite=(.+)$/;
|
|
12
|
+
const qaseIgnoreRegExp = /^@[Qq]ase[Ii][Gg][Nn][Oo][Rr][Ee]$/;
|
|
13
|
+
const qaseTagsRegExp = /^@[Qq]ase[Tt]ags=(.+)$/;
|
|
14
|
+
class TagParser {
|
|
15
|
+
static parse(tags) {
|
|
16
|
+
const tagNames = tags.map((t) => t.name);
|
|
17
|
+
const { legacyIds, projectMapping } = (0, qase_javascript_commons_1.parseProjectMappingFromTags)(tagNames);
|
|
18
|
+
const metadata = {
|
|
19
|
+
ids: [...legacyIds],
|
|
20
|
+
projectMapping: { ...projectMapping },
|
|
21
|
+
fields: {},
|
|
22
|
+
title: null,
|
|
23
|
+
isIgnore: false,
|
|
24
|
+
parameters: {},
|
|
25
|
+
group_params: {},
|
|
26
|
+
suite: null,
|
|
27
|
+
tags: [],
|
|
28
|
+
};
|
|
29
|
+
for (const tag of tags) {
|
|
30
|
+
if (qaseIdRegExp.test(tag.name)) {
|
|
31
|
+
metadata.ids.push(Number(tag.name.replace(/^@[Qq]-?/, '')));
|
|
32
|
+
continue;
|
|
33
|
+
}
|
|
34
|
+
if (newQaseIdRegExp.test(tag.name)) {
|
|
35
|
+
const idsStr = tag.name.replace(/^@[Qq]ase[Ii][Dd]=/, '');
|
|
36
|
+
metadata.ids.push(...idsStr.split(',').map((s) => Number(s.trim())));
|
|
37
|
+
continue;
|
|
38
|
+
}
|
|
39
|
+
if (qaseTitleRegExp.test(tag.name)) {
|
|
40
|
+
metadata.title = tag.name.replace(/^@[Qq]ase[Tt]itle=/, '');
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (qaseFieldsRegExp.test(tag.name)) {
|
|
44
|
+
const value = tag.name.replace(/^@[Qq]ase[Ff]ields=/, '');
|
|
45
|
+
try {
|
|
46
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
47
|
+
const record = JSON.parse(TagParser.normalizeJsonString(value));
|
|
48
|
+
metadata.fields = { ...metadata.fields, ...record };
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
// do nothing
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
if (qaseParametersRegExp.test(tag.name)) {
|
|
55
|
+
const value = tag.name.replace(/^@[Qq]ase[Pp]arameters=/, '');
|
|
56
|
+
try {
|
|
57
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
58
|
+
const record = JSON.parse(TagParser.normalizeJsonString(value));
|
|
59
|
+
metadata.parameters = { ...metadata.parameters, ...record };
|
|
60
|
+
}
|
|
61
|
+
catch {
|
|
62
|
+
// do nothing
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (qaseGroupParametersRegExp.test(tag.name)) {
|
|
66
|
+
const value = tag.name.replace(/^@[Qq]ase[Gg]roup[Pp]arameters=/, '');
|
|
67
|
+
try {
|
|
68
|
+
// eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
|
|
69
|
+
const record = JSON.parse(TagParser.normalizeJsonString(value));
|
|
70
|
+
metadata.group_params = { ...metadata.group_params, ...record };
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
// do nothing
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
if (qaseSuiteRegExp.test(tag.name)) {
|
|
77
|
+
metadata.suite = tag.name.replace(/^@[Qq]ase[Ss]uite=/, '');
|
|
78
|
+
continue;
|
|
79
|
+
}
|
|
80
|
+
if (qaseTagsRegExp.test(tag.name)) {
|
|
81
|
+
const value = tag.name.replace(/^@[Qq]ase[Tt]ags=/, '');
|
|
82
|
+
const parsedTags = value.split(',').map((t) => t.trim()).filter((t) => t.length > 0);
|
|
83
|
+
metadata.tags.push(...parsedTags);
|
|
84
|
+
continue;
|
|
85
|
+
}
|
|
86
|
+
if (qaseIgnoreRegExp.test(tag.name)) {
|
|
87
|
+
metadata.isIgnore = true;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
return metadata;
|
|
91
|
+
}
|
|
92
|
+
static normalizeJsonString(jsonString) {
|
|
93
|
+
if (jsonString.includes("'")) {
|
|
94
|
+
return jsonString.replace(/'/g, '"');
|
|
95
|
+
}
|
|
96
|
+
return jsonString;
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
exports.TagParser = TagParser;
|
package/dist/reporter.d.ts
CHANGED
package/dist/reporter.js
CHANGED
|
@@ -20,11 +20,6 @@ class CucumberQaseReporter extends cucumber_1.Formatter {
|
|
|
20
20
|
* @private
|
|
21
21
|
*/
|
|
22
22
|
reporter;
|
|
23
|
-
/**
|
|
24
|
-
* @type {NetworkProfiler | null}
|
|
25
|
-
* @private
|
|
26
|
-
*/
|
|
27
|
-
profiler = null;
|
|
28
23
|
/**
|
|
29
24
|
* @type {EventEmitter}
|
|
30
25
|
* @private
|
|
@@ -45,15 +40,16 @@ class CucumberQaseReporter extends cucumber_1.Formatter {
|
|
|
45
40
|
frameworkName: 'cucumberjs',
|
|
46
41
|
reporterName: 'cucumberjs-qase-reporter',
|
|
47
42
|
});
|
|
43
|
+
let profiler = null;
|
|
48
44
|
if (composedOptions.profilers?.includes('network')) {
|
|
49
|
-
|
|
45
|
+
profiler = new profilers_1.NetworkProfiler({
|
|
50
46
|
skipDomains: composedOptions.networkProfiler?.skip_domains,
|
|
51
47
|
trackOnFail: composedOptions.networkProfiler?.track_on_fail,
|
|
52
48
|
});
|
|
53
|
-
|
|
49
|
+
profiler.enable();
|
|
54
50
|
}
|
|
55
51
|
this.eventBroadcaster = formatterOptions.eventBroadcaster;
|
|
56
|
-
this.storage = new storage_1.Storage(
|
|
52
|
+
this.storage = new storage_1.Storage(profiler);
|
|
57
53
|
this.bindEventListeners();
|
|
58
54
|
}
|
|
59
55
|
/**
|
|
@@ -99,7 +95,7 @@ class CucumberQaseReporter extends cucumber_1.Formatter {
|
|
|
99
95
|
* @private
|
|
100
96
|
*/
|
|
101
97
|
async publishResults() {
|
|
102
|
-
this.
|
|
98
|
+
this.storage.restore();
|
|
103
99
|
await this.reporter.publish();
|
|
104
100
|
}
|
|
105
101
|
/**
|