Skip to content

Commit a94e501

Browse files
author
Oleksandr_Halichenko
committed
implemented report portal formatter
0 parents  commit a94e501

File tree

4 files changed

+1331
-0
lines changed

4 files changed

+1331
-0
lines changed

README.MD

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
## @yaatp/format-report-portal
2+
This package is formatter for EPAM report portal
3+
4+
### install
5+
`npm install @yaatp/format-report-portal`
6+
7+
### configuration
8+
9+
add formatter to config.js
10+
```javascript
11+
module.exports = {
12+
default: {
13+
format: [
14+
'@yaatp/format-report-portal'
15+
],
16+
formatOptions: {
17+
rpConfig: {
18+
token: 'your token',
19+
endpoint: 'https://your-rp-instance/api/v1',
20+
description: 'Description',
21+
tags: ['Tag'],
22+
project: 'your project',
23+
launch: 'your launch name'
24+
},
25+
}
26+
}
27+
}
28+
```

index.js

Lines changed: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
1+
const { Formatter, Status } = require('@cucumber/cucumber');
2+
const RPClient = require('@reportportal/client-javascript');
3+
class RPFormatter extends Formatter {
4+
launchId = null;
5+
6+
constructor(options) {
7+
super(options);
8+
options.eventBroadcaster.on('envelope', this.processEnvelope.bind(this));
9+
this.rpConfig = options.parsedArgvOptions.rpConfig;
10+
this.rpClient = new RPClient(this.rpConfig);
11+
}
12+
13+
async processEnvelope(envelope) {
14+
if (envelope.testRunStarted) {
15+
await this.startLaunch();
16+
}
17+
else if (envelope.testRunFinished) {
18+
await this.finishLaunch();
19+
}
20+
else if (envelope.testCaseFinished) {
21+
await this.finishTest(envelope);
22+
}
23+
}
24+
25+
async startLaunch() {
26+
const launchObj = this.rpClient.startLaunch({
27+
name: this.rpConfig.launch,
28+
startTime: this.rpClient.helpers.now(),
29+
description: this.rpConfig.description,
30+
attributes: this.rpConfig.tags
31+
});
32+
33+
this.launchId = launchObj.tempId;
34+
this.features = {};
35+
await launchObj.promise;
36+
}
37+
38+
async finishLaunch() {
39+
for (const featureName in this.features) {
40+
await this.rpClient.finishTestItem(this.features[featureName], { status: 'PASSED' }).promise;
41+
}
42+
43+
await this.rpClient.finishLaunch(this.launchId, {
44+
endTime: this.rpClient.helpers.now()
45+
}).promise;
46+
}
47+
48+
async finishTest(envelope) {
49+
const testCase = this.eventDataCollector.getTestCaseAttempt(envelope.testCaseFinished.testCaseStartedId);
50+
const featureName = testCase.gherkinDocument.feature.name;
51+
if (!this.features[featureName]) {
52+
const featureItem = this.rpClient.startTestItem({
53+
description:
54+
this.formatTags(testCase.gherkinDocument.feature.tags) +
55+
'\n' +
56+
testCase.gherkinDocument.feature.description,
57+
name: featureName,
58+
startTime: this.rpClient.helpers.now(),
59+
type: 'SUITE'
60+
}, this.launchId);
61+
this.features[featureName] = featureItem.tempId;
62+
await featureItem.promise;
63+
}
64+
65+
const featureTempId = this.features[featureName]
66+
// Start test item
67+
const testItem = this.rpClient.startTestItem({
68+
description: this.formatTags(testCase.pickle.tags),
69+
name: testCase.pickle.name,
70+
startTime: this.rpClient.helpers.now(),
71+
type: 'STEP'
72+
}, this.launchId, featureTempId);
73+
await testItem.promise;
74+
75+
//send steps
76+
const steps = this.getStepResults(testCase)
77+
for (const step of steps) {
78+
const attachment = step.attachment && step.attachment[0]
79+
? {
80+
name: 'attachment',
81+
type: step.attachment[0].mediaType,
82+
content: step.attachment[0].body
83+
}
84+
: undefined;
85+
await this.rpClient.sendLog(testItem.tempId, {
86+
level: step.result.status === Status.PASSED
87+
? 'INFO'
88+
: 'ERROR',
89+
message: this.getMessage(step),
90+
time: this.rpClient.helpers.now()
91+
}, attachment).promise
92+
}
93+
94+
//finish test item
95+
const status = Object.values(testCase.stepResults).some(step => step.status !== Status.PASSED)
96+
? Status.FAILED.toLowerCase()
97+
: Status.PASSED.toLowerCase()
98+
await this.rpClient.finishTestItem(testItem.tempId, {
99+
status
100+
}).promise;
101+
}
102+
103+
getStepResults(testCase) {
104+
return testCase.testCase.testSteps.map(step => ({
105+
result: testCase.stepResults[step.id],
106+
pickle: testCase.pickle.steps.find(pickle => pickle.id === step.pickleStepId),
107+
attachment: testCase.stepAttachments[step.id]
108+
}))
109+
}
110+
111+
getMessage(step) {
112+
if (!step.pickle) return 'Hook';
113+
const messageParts = [step.pickle.text];
114+
if (step.pickle.argument) {
115+
if (step.pickle.argument.dataTable) messageParts.push(
116+
this.formatTable(step.pickle.argument.dataTable)
117+
)
118+
if (step.pickle.argument.docString) messageParts.push(this.formatDocString(step.pickle.argument.docString))
119+
}
120+
if (step.result.status === Status.FAILED) messageParts.push(step.result.message)
121+
122+
return messageParts.join('\n')
123+
}
124+
125+
formatTable(dataTable) {
126+
const TR = '<tr>';
127+
const TRE = '</tr>';
128+
const TD = '<td>';
129+
const TDE = '</td>';
130+
const formatRow = row => TR + row.cells.map(cell => TD + cell.value + TDE).join('') + TRE;
131+
return '<table><tbody>' + dataTable.rows.map(formatRow).join('') + '</tbody></table>'
132+
}
133+
134+
formatDocString(docString) {
135+
return '<pre><code>' + docString.content + '</code></pre>'
136+
}
137+
138+
formatTags(tags) {
139+
return tags.map(tag => '<code>' + tag.name + '</code>').join('')
140+
}
141+
}
142+
143+
module.exports = RPFormatter

0 commit comments

Comments
 (0)