Skip to content

Commit 03725be

Browse files
authored
Merge pull request #83 from test-results-reporter/80-support-performance-test-results-in-google-chat
feat: support google chat with perf results
2 parents c496715 + 70c6e52 commit 03725be

File tree

7 files changed

+276
-27
lines changed

7 files changed

+276
-27
lines changed

README.md

+3-2
Original file line numberDiff line numberDiff line change
@@ -9,10 +9,11 @@
99
<br />
1010

1111
![Build](https://github.com/test-results-reporter/reporter/workflows/Build/badge.svg?branch=main)
12-
![Downloads](https://img.shields.io/npm/dt/test-results-reporter)
12+
![Downloads](https://img.shields.io/npm/dt/test-results-reporter?logo=npm)
1313
![Size](https://img.shields.io/bundlephobia/minzip/test-results-reporter)
1414

1515
[![Stars](https://img.shields.io/github/stars/test-results-reporter/reporter?style=social)](https://github.com/test-results-reporter/reporter/stargazers)
16+
![Downloads](https://img.shields.io/github/downloads/test-results-reporter/reporter/total?logo=github)
1617

1718
<hr>
1819

@@ -26,7 +27,7 @@
2627

2728
### Test Results
2829

29-
<img height="48" style="margin: 6px;" src="./assets/testng.png" alt="testng" /> <img height="48" style="margin: 6px;" src="./assets/junit.png" alt="junit" /> <img height="48" style="margin: 6px;" src="./assets/cucumber.png" alt="cucumber" /> <img height="48" style="margin: 6px;" src="./assets/mocha.png" alt="mocha" /> <img height="48" style="margin: 6px;" src="./assets/xunit.png" alt="xunit" />
30+
<img height="48" style="margin: 6px;" src="./assets/testng.png" alt="testng" /> <img height="48" style="margin: 6px;" src="./assets/junit.png" alt="junit" /> <img height="48" style="margin: 6px;" src="./assets/cucumber.png" alt="cucumber" /> <img height="48" style="margin: 6px;" src="./assets/mocha.png" alt="mocha" /> <img height="48" style="margin: 6px;" src="./assets/xunit.png" alt="xunit" /> <img height="48" style="margin: 6px;" src="./assets/jmeter.png" alt="jmeter" />
3031

3132
<hr>
3233

assets/jmeter.png

8.49 KB
Loading

src/targets/chat.js

+111-17
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,30 @@ const request = require('phin-retry');
22
const { getTitleText, getResultText, getPercentage, truncate, getPrettyDuration } = require('../helpers/helper');
33
const extension_manager = require('../extensions');
44
const { HOOK } = require('../helpers/constants');
5+
const PerformanceTestResult = require('performance-results-parser/src/models/PerformanceTestResult');
6+
const { getValidMetrics, getMetricValuesText } = require('../helpers/performance');
57

68
async function run({ result, target }) {
79
setTargetInputs(target);
810
const root_payload = getRootPayload();
911
const payload = root_payload.cards[0];
12+
if (result instanceof PerformanceTestResult) {
13+
await setPerformancePayload({ result, target, payload, root_payload });
14+
} else {
15+
await setFunctionalPayload({ result, target, payload, root_payload });
16+
}
17+
return request.post({
18+
url: target.inputs.url,
19+
body: root_payload
20+
});
21+
}
22+
23+
async function setFunctionalPayload({ result, target, payload, root_payload }) {
1024
await extension_manager.run({ result, target, payload, root_payload, hook: HOOK.START });
1125
setMainBlock({ result, target, payload });
1226
await extension_manager.run({ result, target, payload, root_payload, hook: HOOK.POST_MAIN });
1327
setSuiteBlock({ result, target, payload });
1428
await extension_manager.run({ result, target, payload, root_payload, hook: HOOK.END });
15-
return request.post({
16-
url: target.inputs.url,
17-
body: root_payload
18-
});
1929
}
2030

2131
function setTargetInputs(target) {
@@ -39,22 +49,10 @@ function getRootPayload() {
3949
}
4050

4151
function setMainBlock({ result, target, payload }) {
42-
const emoji = result.status === 'PASS' ? '✅' : '❌';
43-
const title_text = getTitleText({ result, target });
52+
const title_text_with_emoji = getTitleTextWithEmoji({ result, target });
4453
const result_text = getResultText({ result });
4554
const duration_text = getPrettyDuration(result.duration, target.inputs.duration);
4655

47-
let title_text_with_emoji = '';
48-
if (target.inputs.include_suites === false) {
49-
title_text_with_emoji = `${emoji} ${title_text}`;
50-
} else if (result.suites.length > 1) {
51-
title_text_with_emoji = title_text;
52-
} else {
53-
title_text_with_emoji = `${emoji} ${title_text}`;
54-
}
55-
if (target.inputs.title_link) {
56-
title_text_with_emoji = `<a href="${target.inputs.title_link}">${title_text_with_emoji}</a>`;
57-
}
5856
const text = `<b>${title_text_with_emoji}</b><br><br><b>Results</b>: ${result_text}<br><b>Duration</b>: ${duration_text}`;
5957
payload.sections.push({
6058
"widgets": [
@@ -118,6 +116,102 @@ function getFailureDetails(suite) {
118116
return text;
119117
}
120118

119+
function getTitleTextWithEmoji({ result, target }) {
120+
const emoji = result.status === 'PASS' ? '✅' : '❌';
121+
const title_text = getTitleText({ result, target });
122+
123+
let title_text_with_emoji = '';
124+
if (target.inputs.include_suites === false) {
125+
title_text_with_emoji = `${emoji} ${title_text}`;
126+
} else if (result.suites && result.suites.length > 1 || result.transactions && result.transactions.length > 1) {
127+
title_text_with_emoji = title_text;
128+
} else {
129+
title_text_with_emoji = `${emoji} ${title_text}`;
130+
}
131+
if (target.inputs.title_link) {
132+
title_text_with_emoji = `<a href="${target.inputs.title_link}">${title_text_with_emoji}</a>`;
133+
}
134+
return title_text_with_emoji;
135+
}
136+
137+
async function setPerformancePayload({ result, target, payload, root_payload }) {
138+
await extension_manager.run({ result, target, payload, root_payload, hook: HOOK.START });
139+
await setPerformanceMainBlock({ result, target, payload });
140+
await extension_manager.run({ result, target, payload, root_payload, hook: HOOK.POST_MAIN });
141+
await setTransactionBlock({ result, target, payload });
142+
await extension_manager.run({ result, target, payload, root_payload, hook: HOOK.END });
143+
}
144+
145+
/**
146+
*
147+
* @param {object} param0
148+
* @param {PerformanceTestResult} param0.result
149+
*/
150+
async function setPerformanceMainBlock({ result, target, payload }) {
151+
const title_text_with_emoji = getTitleTextWithEmoji({ result, target });
152+
const result_text = getResultText({ result });
153+
let text = `<b>${title_text_with_emoji}</b><br><br><b>Results</b>: ${result_text}<br>`;
154+
const valid_metrics = await getValidMetrics({ metrics: result.metrics, target, result });
155+
for (let i = 0; i < valid_metrics.length; i++) {
156+
const metric = valid_metrics[i];
157+
text += `<br><b>${metric.name}</b>: ${getMetricValuesText({ metric, target, result })}`;
158+
}
159+
payload.sections.push({
160+
"widgets": [
161+
{
162+
"textParagraph": {
163+
text
164+
}
165+
}
166+
]
167+
});
168+
}
169+
170+
/**
171+
*
172+
* @param {object} param0
173+
* @param {PerformanceTestResult} param0.result
174+
*/
175+
async function setTransactionBlock({ result, target, payload }) {
176+
if (target.inputs.include_suites) {
177+
let texts = [];
178+
for (let i = 0; i < result.transactions.length; i++) {
179+
const transaction = result.transactions[i];
180+
if (target.inputs.only_failures && transaction.status !== 'FAIL') {
181+
continue;
182+
}
183+
// if transactions length eq to 1 then main block will include suite summary
184+
if (result.transactions.length > 1) {
185+
texts.push(await getTransactionSummary({ target, transaction, }));
186+
}
187+
}
188+
if (texts.length > 0) {
189+
payload.sections.push({
190+
"widgets": [
191+
{
192+
"textParagraph": {
193+
"text": texts.join("<br><br>")
194+
}
195+
}
196+
]
197+
});
198+
}
199+
}
200+
}
201+
202+
async function getTransactionSummary({ target, transaction }) {
203+
const emoji = transaction.status === 'PASS' ? '✅' : '❌';
204+
const suite_title = `${emoji} ${transaction.name}`;
205+
let text = `<b>${suite_title}</b><br>`;
206+
const valid_metrics = await getValidMetrics({ metrics: transaction.metrics, target, result: transaction });
207+
for (let i = 0; i < valid_metrics.length; i++) {
208+
const metric = valid_metrics[i];
209+
text += `<br><b>${metric.name}</b>: ${getMetricValuesText({ metric, target })}`;
210+
}
211+
return text;
212+
}
213+
214+
121215
const default_options = {
122216
condition: 'passOrFail'
123217
};

src/targets/slack.js

+2-2
Original file line numberDiff line numberDiff line change
@@ -191,7 +191,7 @@ async function setPerformanceMainBlock({ result, target, payload }) {
191191
const valid_metrics = await getValidMetrics({ metrics: result.metrics, target, result });
192192
for (let i = 0; i < valid_metrics.length; i++) {
193193
const metric = valid_metrics[i];
194-
text += `\n${metric.name}: ${getMetricValuesText({ metric, target, result })}`;
194+
text += `\n*${metric.name}*: ${getMetricValuesText({ metric, target, result })}`;
195195
}
196196
payload.blocks.push({
197197
"type": "section",
@@ -220,7 +220,7 @@ async function setTransactionBlock({ result, target, payload }) {
220220
const valid_metrics = await getValidMetrics({ metrics: transaction.metrics, target, result });
221221
for (let i = 0; i < valid_metrics.length; i++) {
222222
const metric = valid_metrics[i];
223-
text += `\n${metric.name}: ${getMetricValuesText({ metric, target, result })}`;
223+
text += `\n*${metric.name}*: ${getMetricValuesText({ metric, target, result })}`;
224224
}
225225
payload.blocks.push({
226226
"type": "section",

test/mocks/chat.mock.js

+76
Original file line numberDiff line numberDiff line change
@@ -440,4 +440,80 @@ addInteractionHandler('post test-summary to chat with title_link', () => {
440440
status: 200
441441
}
442442
}
443+
});
444+
445+
addInteractionHandler('post test-summary to chat for JMeter', () => {
446+
return {
447+
request: {
448+
method: 'POST',
449+
path: '/message',
450+
body: {
451+
"cards": [
452+
{
453+
"sections": [
454+
{
455+
"widgets": [
456+
{
457+
"textParagraph": {
458+
"text": "<b>TOTAL</b><br><br><b>Results</b>: undefined / undefined Passed (0%)<br><br><b>Samples</b>: 39 0.55535/s<br><b>Duration</b>: avg=4.6s | min=1.1s | med=3.3s | max=15.5s | p90=11.3s | p95=11.4s | p99=15.5s<br><b>Errors</b>: 0 %<br><b>Data Sent</b>: 0 38.87 KB/sec<br><b>Data Received</b>: 0 5166.44 KB/sec"
459+
}
460+
}
461+
]
462+
},
463+
{
464+
"widgets": [
465+
{
466+
"textParagraph": {
467+
"text": "<b>✅ S01_T01_Application_Launch</b><br><br><b>Samples</b>: 10 0.14422/s<br><b>Duration</b>: avg=3s | min=2.1s | med=2.8s | max=3.7s | p90=3.7s | p95=3.7s | p99=3.7s<br><b>Errors</b>: 0.001 %<br><b>Data Sent</b>: 0 5.36 KB/sec<br><b>Data Received</b>: 0 2662.79 KB/sec<br><br><b>✅ S01_T02_Application_Login</b><br><br><b>Samples</b>: 9 0.1461/s<br><b>Duration</b>: avg=4.3s | min=3s | med=3.2s | max=10.7s | p90=4.4s | p95=10.7s | p99=10.7s<br><b>Errors</b>: 0 %<br><b>Data Sent</b>: 0 12.94 KB/sec<br><b>Data Received</b>: 0 2754.9 KB/sec"
468+
}
469+
}
470+
]
471+
}
472+
]
473+
}
474+
]
475+
}
476+
},
477+
response: {
478+
status: 200
479+
}
480+
}
481+
});
482+
483+
addInteractionHandler('post test-summary with failures to chat for failed JMeter', () => {
484+
return {
485+
request: {
486+
method: 'POST',
487+
path: '/message',
488+
body: {
489+
"cards": [
490+
{
491+
"sections": [
492+
{
493+
"widgets": [
494+
{
495+
"textParagraph": {
496+
"text": "<b>TOTAL 1.2.3</b><br><br><b>Results</b>: undefined / undefined Passed (0%)<br><br><b>Samples</b>: 39 0.55535/s<br><b>Duration</b>: 🔺 avg=4.6s (+1.1s) | min=1.1s | med=3.3s | max=15.5s | p90=11.3s | p95=11.4s | p99=15.5s<br><b>Errors</b>: 0 %<br><b>Data Sent</b>: 0 38.87 KB/sec<br><b>Data Received</b>: 0 5166.44 KB/sec"
497+
}
498+
}
499+
]
500+
},
501+
{
502+
"widgets": [
503+
{
504+
"textParagraph": {
505+
"text": "<b>❌ S01_T02_Application_Login</b><br><br><b>Samples</b>: 🔻 9 (-1) 0.1461/s<br><b>Duration</b>: 🔺 avg=4.3s (+855ms) | min=3s | med=3.2s | max=10.7s | p90=4.4s | p95=10.7s | p99=10.7s<br><b>Errors</b>: 0 %<br><b>Data Sent</b>: 0 12.94 KB/sec<br><b>Data Received</b>: 0 2754.9 KB/sec"
506+
}
507+
}
508+
]
509+
}
510+
]
511+
}
512+
]
513+
}
514+
},
515+
response: {
516+
status: 200
517+
}
518+
}
443519
});

test/mocks/slack.mock.js

+5-5
Original file line numberDiff line numberDiff line change
@@ -520,21 +520,21 @@ addInteractionHandler('post test-summary to slack for JMeter', () => {
520520
"type": "section",
521521
"text": {
522522
"type": "mrkdwn",
523-
"text": "*TOTAL*\n\n*Results*: 2 / 2 Passed (100%)\nSamples: 39 0.55535/s\nDuration: avg=4.6s | min=1.1s | med=3.3s | max=15.5s | p90=11.3s | p95=11.4s | p99=15.5s\nErrors: 0 %\nData Sent: 0 38.87 KB/sec\nData Received: 0 5166.44 KB/sec"
523+
"text": "*TOTAL*\n\n*Results*: 2 / 2 Passed (100%)\n*Samples*: 39 0.55535/s\n*Duration*: avg=4.6s | min=1.1s | med=3.3s | max=15.5s | p90=11.3s | p95=11.4s | p99=15.5s\n*Errors*: 0 %\n*Data Sent*: 0 38.87 KB/sec\n*Data Received*: 0 5166.44 KB/sec"
524524
}
525525
},
526526
{
527527
"type": "section",
528528
"text": {
529529
"type": "mrkdwn",
530-
"text": "*S01_T01_Application_Launch*\n\nSamples: 10 0.14422/s\nDuration: avg=3s | min=2.1s | med=2.8s | max=3.7s | p90=3.7s | p95=3.7s | p99=3.7s\nErrors: 0.001 %\nData Sent: 0 5.36 KB/sec\nData Received: 0 2662.79 KB/sec"
530+
"text": "*S01_T01_Application_Launch*\n\n*Samples*: 10 0.14422/s\n*Duration*: avg=3s | min=2.1s | med=2.8s | max=3.7s | p90=3.7s | p95=3.7s | p99=3.7s\n*Errors*: 0.001 %\n*Data Sent*: 0 5.36 KB/sec\n*Data Received*: 0 2662.79 KB/sec"
531531
}
532532
},
533533
{
534534
"type": "section",
535535
"text": {
536536
"type": "mrkdwn",
537-
"text": "*S01_T02_Application_Login*\n\nSamples: 9 0.1461/s\nDuration: avg=4.3s | min=3s | med=3.2s | max=10.7s | p90=4.4s | p95=10.7s | p99=10.7s\nErrors: 0 %\nData Sent: 0 12.94 KB/sec\nData Received: 0 2754.9 KB/sec"
537+
"text": "*S01_T02_Application_Login*\n\n*Samples*: 9 0.1461/s\n*Duration*: avg=4.3s | min=3s | med=3.2s | max=10.7s | p90=4.4s | p95=10.7s | p99=10.7s\n*Errors*: 0 %\n*Data Sent*: 0 12.94 KB/sec\n*Data Received*: 0 2754.9 KB/sec"
538538
}
539539
}
540540
]
@@ -562,14 +562,14 @@ addInteractionHandler('post test-summary with failures to slack for failed JMete
562562
"type": "section",
563563
"text": {
564564
"type": "mrkdwn",
565-
"text": "*TOTAL 1.2.3*\n\n*Results*: 1 / 2 Passed (50%)\nSamples: 39 0.55535/s\nDuration: 🔺 avg=4.6s (+1.1s) | min=1.1s | med=3.3s | max=15.5s | p90=11.3s | p95=11.4s | p99=15.5s\nErrors: 0 %\nData Sent: 0 38.87 KB/sec\nData Received: 0 5166.44 KB/sec"
565+
"text": "*TOTAL 1.2.3*\n\n*Results*: 1 / 2 Passed (50%)\n*Samples*: 39 0.55535/s\n*Duration*: 🔺 avg=4.6s (+1.1s) | min=1.1s | med=3.3s | max=15.5s | p90=11.3s | p95=11.4s | p99=15.5s\n*Errors*: 0 %\n*Data Sent*: 0 38.87 KB/sec\n*Data Received*: 0 5166.44 KB/sec"
566566
}
567567
},
568568
{
569569
"type": "section",
570570
"text": {
571571
"type": "mrkdwn",
572-
"text": "*S01_T02_Application_Login 1.2.3*\n\nSamples: 🔻 9 (-1) 0.1461/s\nDuration: 🔺 avg=4.3s (+855ms) | min=3s | med=3.2s | max=10.7s | p90=4.4s | p95=10.7s | p99=10.7s\nErrors: 0 %\nData Sent: 0 12.94 KB/sec\nData Received: 0 2754.9 KB/sec"
572+
"text": "*S01_T02_Application_Login 1.2.3*\n\n*Samples*: 🔻 9 (-1) 0.1461/s\n*Duration*: 🔺 avg=4.3s (+855ms) | min=3s | med=3.2s | max=10.7s | p90=4.4s | p95=10.7s | p99=10.7s\n*Errors*: 0 %\n*Data Sent*: 0 12.94 KB/sec\n*Data Received*: 0 2754.9 KB/sec"
573573
}
574574
}
575575
]

0 commit comments

Comments
 (0)