playwright-slack-report 1.0.18 â 1.0.20
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/README.md +239 -30
- package/dist/src/LayoutGenerator.d.ts +4 -4
- package/dist/src/LayoutGenerator.js +68 -68
- package/dist/src/ResultsParser.d.ts +46 -46
- package/dist/src/ResultsParser.js +118 -118
- package/dist/src/SlackClient.d.ts +24 -23
- package/dist/src/SlackClient.js +62 -59
- package/dist/src/SlackReporter.d.ts +21 -20
- package/dist/src/SlackReporter.js +112 -102
- package/dist/src/custom_block/my_block.d.ts +4 -4
- package/dist/src/custom_block/my_block.js +86 -86
- package/dist/src/custom_block/simple.d.ts +3 -3
- package/dist/src/custom_block/simple.js +16 -16
- package/dist/src/custom_block/simple_with_meta.d.ts +3 -3
- package/dist/src/custom_block/simple_with_meta.js +30 -30
- package/dist/src/index.d.ts +32 -32
- package/dist/src/index.js +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# playwright-slack-report  [](https://github.com/ryanrosello-og/playwright-slack-report/blob/master/LICENSE) [](https://coveralls.io/github/ryanrosello-og/playwright-slack-report?branch=main)
|
|
2
2
|
|
|
3
3
|
[](https://gitpod.io/#https://github.com/ryanrosello-og/playwright-slack-report)
|
|
4
4
|
|
|
@@ -16,7 +16,7 @@ Publish your Playwright test results to your favorite Slack channel(s).
|
|
|
16
16
|
- đ§âđ¨ Define your own custom Slack message layout!
|
|
17
17
|
|
|
18
18
|
|
|
19
|
-
# đĻ Installation
|
|
19
|
+
# đĻ Installation
|
|
20
20
|
|
|
21
21
|
Run following commands:
|
|
22
22
|
|
|
@@ -47,7 +47,12 @@ Run your tests by providing your` SLACK_BOT_USER_OAUTH_TOKEN` as an environment
|
|
|
47
47
|
|
|
48
48
|
`SLACK_BOT_USER_OAUTH_TOKEN=[your Slack bot user OAUTH token] npx playwright test`
|
|
49
49
|
|
|
50
|
-
|
|
50
|
+
> **NOTE:** The Slack channel that you specify will need to be *public*, this app will not be able to publish messages to private channels.
|
|
51
|
+
|
|
52
|
+
---
|
|
53
|
+
|
|
54
|
+
<details>
|
|
55
|
+
<summary><b>đ How do I find my Slack bot oauth token?</b></summary>
|
|
51
56
|
|
|
52
57
|
You will need to have Slack administrator rights to perform the steps below.
|
|
53
58
|
|
|
@@ -68,9 +73,9 @@ You will need to have Slack administrator rights to perform the steps below.
|
|
|
68
73
|
|
|
69
74
|

|
|
70
75
|
|
|
71
|
-
* chat:write
|
|
72
|
-
* chat:write.public
|
|
73
|
-
* chat:write.customize
|
|
76
|
+
* chat:write
|
|
77
|
+
* chat:write.public
|
|
78
|
+
* chat:write.customize
|
|
74
79
|
|
|
75
80
|
6. Scroll up to the OAuth Tokens for Your Workspace and click the **Install to Workspace** button
|
|
76
81
|
|
|
@@ -80,12 +85,16 @@ You will need to have Slack administrator rights to perform the steps below.
|
|
|
80
85
|
|
|
81
86
|

|
|
82
87
|
|
|
83
|
-
The final step will be to copy the generated Bot User OAuth Token aka `SLACK_BOT_USER_OAUTH_TOKEN`.
|
|
88
|
+
The final step will be to copy the generated Bot User OAuth Token aka `SLACK_BOT_USER_OAUTH_TOKEN`.
|
|
84
89
|
|
|
85
90
|
>**Treat this token as a secret.**
|
|
86
91
|
|
|
87
92
|

|
|
88
93
|
|
|
94
|
+
</details>
|
|
95
|
+
|
|
96
|
+
---
|
|
97
|
+
|
|
89
98
|
# âī¸ Configuration
|
|
90
99
|
|
|
91
100
|
An example advanced configuration is shown below:
|
|
@@ -102,29 +111,30 @@ An example advanced configuration is shown below:
|
|
|
102
111
|
{
|
|
103
112
|
channels: ["pw-tests", "ci"], // provide one or more Slack channels
|
|
104
113
|
sendResults: "always", // "always" , "on-failure", "off"
|
|
114
|
+
layout: generateCustomLayout,
|
|
115
|
+
maxNumberOfFailuresToShow: 4,
|
|
116
|
+
meta: [
|
|
117
|
+
{
|
|
118
|
+
key: 'BUILD_NUMBER',
|
|
119
|
+
value: '323332-2341',
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
key: 'WHATEVER_ENV_VARIABLE',
|
|
123
|
+
value: process.env.SOME_ENV_VARIABLE, // depending on your CI environment, this can be the branch name, build id, etc
|
|
124
|
+
},
|
|
125
|
+
{
|
|
126
|
+
key: 'HTML Results',
|
|
127
|
+
value: '<https://your-build-artifacts.my.company.dev/pw/23887/playwright-report/index.html|đ>',
|
|
128
|
+
},
|
|
129
|
+
],
|
|
105
130
|
},
|
|
106
|
-
|
|
107
|
-
maxNumberOfFailuresToShow: 4,
|
|
108
|
-
meta: [
|
|
109
|
-
{
|
|
110
|
-
key: 'BUILD_NUMBER',
|
|
111
|
-
value: '323332-2341',
|
|
112
|
-
},
|
|
113
|
-
{
|
|
114
|
-
key: 'WHATEVER_ENV_VARIABLE',
|
|
115
|
-
value: process.env.SOME_ENV_VARIABLE, // depending on your CI environment, this can be the branch name, build id, etc
|
|
116
|
-
},
|
|
117
|
-
{
|
|
118
|
-
key: 'HTML Results',
|
|
119
|
-
value: '<https://your-build-artifacts.my.company.dev/pw/23887/playwright-report/index.html|đ>',
|
|
120
|
-
},
|
|
121
|
-
],
|
|
131
|
+
|
|
122
132
|
],
|
|
123
133
|
],
|
|
124
134
|
```
|
|
125
135
|
|
|
126
136
|
### **channels**
|
|
127
|
-
An array of Slack channels to post to,
|
|
137
|
+
An array of Slack channels to post to, at least one channel is required
|
|
128
138
|
### **sendResults**
|
|
129
139
|
Can either be *"always"*, *"on-failure"* or *"off"*, this configuration is required:
|
|
130
140
|
* **always** - will send the results to Slack at completion of the test run
|
|
@@ -133,6 +143,8 @@ Can either be *"always"*, *"on-failure"* or *"off"*, this configuration is requi
|
|
|
133
143
|
### **layout**
|
|
134
144
|
A function that returns a layout object, this configuration is optional. See section below for more details.
|
|
135
145
|
* meta - an array of meta data to be sent to Slack, this configuration is optional.
|
|
146
|
+
### **layoutAsync**
|
|
147
|
+
Same as **layout** above, but asynchronous in that it returns a promise.
|
|
136
148
|
### **maxNumberOfFailuresToShow**
|
|
137
149
|
Limits the number of failures shown in the Slack message, defaults to 10.
|
|
138
150
|
|
|
@@ -152,7 +164,7 @@ meta: [
|
|
|
152
164
|
key: 'GITHUB_REF',
|
|
153
165
|
value: process.env.GITHUB_REF,
|
|
154
166
|
},
|
|
155
|
-
],
|
|
167
|
+
],
|
|
156
168
|
...
|
|
157
169
|
```
|
|
158
170
|
|
|
@@ -178,7 +190,7 @@ const generateCustomLayout = (summaryResults: SummaryResults):Array<KnownBlock |
|
|
|
178
190
|
export default generateCustomLayout;
|
|
179
191
|
```
|
|
180
192
|
|
|
181
|
-
In your, `playwright.
|
|
193
|
+
In your, `playwright.config.ts` file, add your function into the config.
|
|
182
194
|
|
|
183
195
|
```typescript
|
|
184
196
|
import { generateCustomLayout } from "./my_custom_layout";
|
|
@@ -191,9 +203,9 @@ In your, `playwright.confing.ts` file, add your function into the config.
|
|
|
191
203
|
{
|
|
192
204
|
channels: ["pw-tests", "ci"], // provide one or more Slack channels
|
|
193
205
|
sendResults: "always", // "always" , "on-failure", "off"
|
|
206
|
+
layout: generateCustomLayout,
|
|
207
|
+
...
|
|
194
208
|
},
|
|
195
|
-
layout: generateCustomLayout,
|
|
196
|
-
...
|
|
197
209
|
],
|
|
198
210
|
],
|
|
199
211
|
```
|
|
@@ -250,7 +262,6 @@ Add the meta block in your config:
|
|
|
250
262
|
},
|
|
251
263
|
],
|
|
252
264
|
},
|
|
253
|
-
|
|
254
265
|
],
|
|
255
266
|
],
|
|
256
267
|
```
|
|
@@ -298,6 +309,204 @@ Generates the following message in Slack:
|
|
|
298
309
|
|
|
299
310
|

|
|
300
311
|
|
|
312
|
+
|
|
313
|
+
**Example 3: - with screenshots and/or recorded videos**
|
|
314
|
+
|
|
315
|
+
In your, `playwright.config.ts` file, add these params (Make sure you use **layoutAsync** rather than **layout**):
|
|
316
|
+
|
|
317
|
+
```typescript
|
|
318
|
+
import { generateCustomLayoutAsync } from "./my_custom_layout";
|
|
319
|
+
...
|
|
320
|
+
reporter: [
|
|
321
|
+
[
|
|
322
|
+
"./node_modules/playwright-slack-report/dist/src/SlackReporter.js",
|
|
323
|
+
{
|
|
324
|
+
...
|
|
325
|
+
layoutAsync: generateCustomLayoutAsync,
|
|
326
|
+
...
|
|
327
|
+
},
|
|
328
|
+
],
|
|
329
|
+
],
|
|
330
|
+
use: {
|
|
331
|
+
...
|
|
332
|
+
screenshot: "only-on-failure",
|
|
333
|
+
video: "retain-on-failure",
|
|
334
|
+
...
|
|
335
|
+
},
|
|
336
|
+
```
|
|
337
|
+
|
|
338
|
+
Create the function to generate the layout asynchronously in `my_custom_layout.ts`:
|
|
339
|
+
|
|
340
|
+
```typescript
|
|
341
|
+
import fs from "fs";
|
|
342
|
+
import path from "path";
|
|
343
|
+
import { Block, KnownBlock } from "@slack/types";
|
|
344
|
+
import { SummaryResults } from "playwright-slack-report/dist/src";
|
|
345
|
+
import { PutObjectCommand, S3Client } from "@aws-sdk/client-s3";
|
|
346
|
+
|
|
347
|
+
const s3Client = new S3Client({
|
|
348
|
+
credentials: {
|
|
349
|
+
accessKeyId: process.env.S3_ACCESS_KEY || "",
|
|
350
|
+
secretAccessKey: process.env.S3_SECRET || "",
|
|
351
|
+
},
|
|
352
|
+
region: process.env.S3_REGION,
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
async function uploadFile(filePath, fileName) {
|
|
356
|
+
try {
|
|
357
|
+
const ext = path.extname(filePath);
|
|
358
|
+
const name = `${fileName}${ext}`;
|
|
359
|
+
|
|
360
|
+
await s3Client.send(
|
|
361
|
+
new PutObjectCommand({
|
|
362
|
+
Bucket: process.env.S3_BUCKET,
|
|
363
|
+
Key: name,
|
|
364
|
+
Body: fs.createReadStream(filePath),
|
|
365
|
+
})
|
|
366
|
+
);
|
|
367
|
+
|
|
368
|
+
return `https://${process.env.S3_BUCKET}.s3.${process.env.S3_REGION}.amazonaws.com/${name}`;
|
|
369
|
+
} catch (err) {
|
|
370
|
+
console.log("đĨđĨ Error", err);
|
|
371
|
+
}
|
|
372
|
+
}
|
|
373
|
+
|
|
374
|
+
|
|
375
|
+
export async function generateCustomLayoutAsync (summaryResults: SummaryResults): Promise<Array<KnownBlock | Block>> {
|
|
376
|
+
const { tests } = summaryResults;
|
|
377
|
+
// create your custom slack blocks
|
|
378
|
+
|
|
379
|
+
const header = {
|
|
380
|
+
type: "header",
|
|
381
|
+
text: {
|
|
382
|
+
type: "plain_text",
|
|
383
|
+
text: "đ *Playwright E2E Test Results*",
|
|
384
|
+
emoji: true,
|
|
385
|
+
},
|
|
386
|
+
};
|
|
387
|
+
|
|
388
|
+
const summary = {
|
|
389
|
+
type: "section",
|
|
390
|
+
text: {
|
|
391
|
+
type: "mrkdwn",
|
|
392
|
+
text: `â
*${summaryResults.passed}* | â *${summaryResults.failed}* | ⊠*${summaryResults.skipped}*`,
|
|
393
|
+
},
|
|
394
|
+
};
|
|
395
|
+
|
|
396
|
+
const fails: Array<KnownBlock | Block> = [];
|
|
397
|
+
|
|
398
|
+
for (const t of tests) {
|
|
399
|
+
if (t.status === "failed" || t.status === "timedOut") {
|
|
400
|
+
|
|
401
|
+
fails.push({
|
|
402
|
+
type: "section",
|
|
403
|
+
text: {
|
|
404
|
+
type: "mrkdwn",
|
|
405
|
+
text: `đ *[${t.browser}] | ${t.suiteName.replace(/\W/gi, "-")}*`,
|
|
406
|
+
},
|
|
407
|
+
});
|
|
408
|
+
|
|
409
|
+
const assets: Array<string> = [];
|
|
410
|
+
|
|
411
|
+
if (t.attachments) {
|
|
412
|
+
for (const a of t.attachments) {
|
|
413
|
+
// Upload failed tests screenshots and videos to the service of your choice
|
|
414
|
+
// In my case I upload the to S3 bucket
|
|
415
|
+
const permalink = await uploadFile(
|
|
416
|
+
a.path,
|
|
417
|
+
`${t.suiteName}--${t.name}`.replace(/\W/gi, "-").toLowerCase()
|
|
418
|
+
);
|
|
419
|
+
|
|
420
|
+
if (permalink) {
|
|
421
|
+
let icon = "";
|
|
422
|
+
if (a.name === "screenshot") {
|
|
423
|
+
icon = "đ¸";
|
|
424
|
+
} else if (a.name === "video") {
|
|
425
|
+
icon = "đĨ";
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
assets.push(`${icon} See the <${permalink}|${a.name}>`);
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
}
|
|
432
|
+
|
|
433
|
+
if (assets.length > 0) {
|
|
434
|
+
fails.push({
|
|
435
|
+
type: "context",
|
|
436
|
+
elements: [{ type: "mrkdwn", text: assets.join("\n") }],
|
|
437
|
+
});
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
}
|
|
441
|
+
|
|
442
|
+
return [header, summary, { type: "divider" }, ...fails]
|
|
443
|
+
}
|
|
444
|
+
|
|
445
|
+
```
|
|
446
|
+
|
|
447
|
+
**Also you can upload the attachments to slack.** But it might be more expensive for you and also you'll have to extend the scope.
|
|
448
|
+
|
|
449
|
+
```typescript
|
|
450
|
+
...
|
|
451
|
+
const web_api_1 = require('@slack/web-api');
|
|
452
|
+
const slackClient = new web_api_1.WebClient(process.env.SLACK_BOT_USER_OAUTH_TOKEN);
|
|
453
|
+
|
|
454
|
+
async function uploadFile(filePath) {
|
|
455
|
+
try {
|
|
456
|
+
const result = await slackClient.files.uploadV2({
|
|
457
|
+
channels: 'you_cannel_name',
|
|
458
|
+
file: fs.createReadStream(filePath),
|
|
459
|
+
filename: filePath.split('/').at(-1),
|
|
460
|
+
});
|
|
461
|
+
|
|
462
|
+
return result.file;
|
|
463
|
+
} catch (error) {
|
|
464
|
+
console.log('đĨđĨ error', error);
|
|
465
|
+
}
|
|
466
|
+
}
|
|
467
|
+
|
|
468
|
+
export async function generateCustomLayoutAsync (summaryResults: SummaryResults): Promise<Array<KnownBlock | Block>> {
|
|
469
|
+
const { tests } = summaryResults;
|
|
470
|
+
....
|
|
471
|
+
// See the snippet above ^^^
|
|
472
|
+
|
|
473
|
+
|
|
474
|
+
if (t.attachments) {
|
|
475
|
+
for (const a of t.attachments) {
|
|
476
|
+
const file = await uploadFile(a.path);
|
|
477
|
+
|
|
478
|
+
if (file) {
|
|
479
|
+
if (a.name === 'screenshot' && file.permalink) {
|
|
480
|
+
fails.push({
|
|
481
|
+
alt_text: '',
|
|
482
|
+
image_url: file.permalink,
|
|
483
|
+
title: { type: 'plain_text', text: file.name || '' },
|
|
484
|
+
type: 'image',
|
|
485
|
+
});
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
if (a.name === 'video' && file.permalink) {
|
|
489
|
+
fails.push({
|
|
490
|
+
alt_text: '',
|
|
491
|
+
// NOTE:
|
|
492
|
+
// Slack requires thumbnail_url length to be more that 0
|
|
493
|
+
// Either set screenshot url as the thumbnail or add a placeholder image url
|
|
494
|
+
thumbnail_url: '',
|
|
495
|
+
title: { type: 'plain_text', text: file.name || '' },
|
|
496
|
+
type: 'video',
|
|
497
|
+
video_url: file.permalink,
|
|
498
|
+
});
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
}
|
|
503
|
+
....
|
|
504
|
+
|
|
505
|
+
return [header, summary, { type: "divider" }, ...fails]
|
|
506
|
+
}
|
|
507
|
+
|
|
508
|
+
```
|
|
509
|
+
|
|
301
510
|
# đ License
|
|
302
511
|
|
|
303
512
|
[MIT](https://github.com/ryanrosello-og/playwright-slack-report/blob/main/LICENSE)
|
|
@@ -314,7 +523,7 @@ Run the tests using `npm run pw`
|
|
|
314
523
|
Run `npm pack`
|
|
315
524
|
|
|
316
525
|
Create a new playwright project using `yarn create playwright`
|
|
317
|
-
Modify the `package.json` and a local dependancy to the generated `tgz` file
|
|
526
|
+
Modify the `package.json` and a local dependancy to the generated `tgz` file
|
|
318
527
|
|
|
319
528
|
e.g.
|
|
320
529
|
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { KnownBlock, Block } from '@slack/types';
|
|
2
|
-
import { SummaryResults } from '.';
|
|
3
|
-
declare const generateBlocks: (summaryResults: SummaryResults, maxNumberOfFailures: number) => Promise<Array<KnownBlock | Block>>;
|
|
4
|
-
export default generateBlocks;
|
|
1
|
+
import { KnownBlock, Block } from '@slack/types';
|
|
2
|
+
import { SummaryResults } from '.';
|
|
3
|
+
declare const generateBlocks: (summaryResults: SummaryResults, maxNumberOfFailures: number) => Promise<Array<KnownBlock | Block>>;
|
|
4
|
+
export default generateBlocks;
|
|
@@ -1,69 +1,69 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
-
const generateBlocks = async (summaryResults, maxNumberOfFailures) => {
|
|
4
|
-
const maxNumberOfFailureLength = 650;
|
|
5
|
-
const fails = [];
|
|
6
|
-
const meta = [];
|
|
7
|
-
const header = {
|
|
8
|
-
type: 'section',
|
|
9
|
-
text: {
|
|
10
|
-
type: 'mrkdwn',
|
|
11
|
-
text: 'đ *Playwright Results*',
|
|
12
|
-
},
|
|
13
|
-
};
|
|
14
|
-
const summary = {
|
|
15
|
-
type: 'section',
|
|
16
|
-
text: {
|
|
17
|
-
type: 'mrkdwn',
|
|
18
|
-
text: `â
*${summaryResults.passed}* | â *${summaryResults.failed}* | ⊠*${summaryResults.skipped}*`,
|
|
19
|
-
},
|
|
20
|
-
};
|
|
21
|
-
for (let i = 0; i < summaryResults.failures.length; i += 1) {
|
|
22
|
-
const { failureReason, test } = summaryResults.failures[i];
|
|
23
|
-
const formattedFailure = failureReason
|
|
24
|
-
.substring(0, maxNumberOfFailureLength)
|
|
25
|
-
.split('\n')
|
|
26
|
-
.map((l) => `>${l}`)
|
|
27
|
-
.join('\n');
|
|
28
|
-
fails.push({
|
|
29
|
-
type: 'section',
|
|
30
|
-
text: {
|
|
31
|
-
type: 'mrkdwn',
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
const generateBlocks = async (summaryResults, maxNumberOfFailures) => {
|
|
4
|
+
const maxNumberOfFailureLength = 650;
|
|
5
|
+
const fails = [];
|
|
6
|
+
const meta = [];
|
|
7
|
+
const header = {
|
|
8
|
+
type: 'section',
|
|
9
|
+
text: {
|
|
10
|
+
type: 'mrkdwn',
|
|
11
|
+
text: 'đ *Playwright Results*',
|
|
12
|
+
},
|
|
13
|
+
};
|
|
14
|
+
const summary = {
|
|
15
|
+
type: 'section',
|
|
16
|
+
text: {
|
|
17
|
+
type: 'mrkdwn',
|
|
18
|
+
text: `â
*${summaryResults.passed}* | â *${summaryResults.failed}* | ⊠*${summaryResults.skipped}*`,
|
|
19
|
+
},
|
|
20
|
+
};
|
|
21
|
+
for (let i = 0; i < summaryResults.failures.length; i += 1) {
|
|
22
|
+
const { failureReason, test } = summaryResults.failures[i];
|
|
23
|
+
const formattedFailure = failureReason
|
|
24
|
+
.substring(0, maxNumberOfFailureLength)
|
|
25
|
+
.split('\n')
|
|
26
|
+
.map((l) => `>${l}`)
|
|
27
|
+
.join('\n');
|
|
28
|
+
fails.push({
|
|
29
|
+
type: 'section',
|
|
30
|
+
text: {
|
|
31
|
+
type: 'mrkdwn',
|
|
32
32
|
text: `*${test}*
|
|
33
|
-
\n${formattedFailure}`,
|
|
34
|
-
},
|
|
35
|
-
});
|
|
36
|
-
if (i > maxNumberOfFailures) {
|
|
37
|
-
fails.push({
|
|
38
|
-
type: 'section',
|
|
39
|
-
text: {
|
|
40
|
-
type: 'mrkdwn',
|
|
41
|
-
text: `*There are too many failures to display - ${fails.length} out of ${summaryResults.failures.length} failures shown*`,
|
|
42
|
-
},
|
|
43
|
-
});
|
|
44
|
-
break;
|
|
45
|
-
}
|
|
46
|
-
}
|
|
47
|
-
if (summaryResults.meta) {
|
|
48
|
-
for (let i = 0; i < summaryResults.meta.length; i += 1) {
|
|
49
|
-
const { key, value } = summaryResults.meta[i];
|
|
50
|
-
meta.push({
|
|
51
|
-
type: 'section',
|
|
52
|
-
text: {
|
|
53
|
-
type: 'mrkdwn',
|
|
54
|
-
text: `\n*${key}* :\t${value}`,
|
|
55
|
-
},
|
|
56
|
-
});
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
return [
|
|
60
|
-
header,
|
|
61
|
-
summary,
|
|
62
|
-
...meta,
|
|
63
|
-
{
|
|
64
|
-
type: 'divider',
|
|
65
|
-
},
|
|
66
|
-
...fails,
|
|
67
|
-
];
|
|
68
|
-
};
|
|
69
|
-
exports.default = generateBlocks;
|
|
33
|
+
\n${formattedFailure}`,
|
|
34
|
+
},
|
|
35
|
+
});
|
|
36
|
+
if (i > maxNumberOfFailures) {
|
|
37
|
+
fails.push({
|
|
38
|
+
type: 'section',
|
|
39
|
+
text: {
|
|
40
|
+
type: 'mrkdwn',
|
|
41
|
+
text: `*There are too many failures to display - ${fails.length} out of ${summaryResults.failures.length} failures shown*`,
|
|
42
|
+
},
|
|
43
|
+
});
|
|
44
|
+
break;
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
if (summaryResults.meta) {
|
|
48
|
+
for (let i = 0; i < summaryResults.meta.length; i += 1) {
|
|
49
|
+
const { key, value } = summaryResults.meta[i];
|
|
50
|
+
meta.push({
|
|
51
|
+
type: 'section',
|
|
52
|
+
text: {
|
|
53
|
+
type: 'mrkdwn',
|
|
54
|
+
text: `\n*${key}* :\t${value}`,
|
|
55
|
+
},
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
return [
|
|
60
|
+
header,
|
|
61
|
+
summary,
|
|
62
|
+
...meta,
|
|
63
|
+
{
|
|
64
|
+
type: 'divider',
|
|
65
|
+
},
|
|
66
|
+
...fails,
|
|
67
|
+
];
|
|
68
|
+
};
|
|
69
|
+
exports.default = generateBlocks;
|
|
@@ -1,46 +1,46 @@
|
|
|
1
|
-
/// <reference types="node" />
|
|
2
|
-
import { failure, SummaryResults } from '.';
|
|
3
|
-
export declare type testResult = {
|
|
4
|
-
suiteName: string;
|
|
5
|
-
name: string;
|
|
6
|
-
browser?: string;
|
|
7
|
-
projectName: string;
|
|
8
|
-
endedAt: string;
|
|
9
|
-
reason: string;
|
|
10
|
-
retry: number;
|
|
11
|
-
retries: number;
|
|
12
|
-
startedAt: string;
|
|
13
|
-
status: 'passed' | 'failed' | 'timedOut' | 'skipped';
|
|
14
|
-
attachments?: {
|
|
15
|
-
body: string | undefined | Buffer;
|
|
16
|
-
contentType: string;
|
|
17
|
-
name: string;
|
|
18
|
-
path: string;
|
|
19
|
-
}[];
|
|
20
|
-
};
|
|
21
|
-
export declare type testSuite = {
|
|
22
|
-
testSuite: {
|
|
23
|
-
title: string;
|
|
24
|
-
tests: testResult[];
|
|
25
|
-
testRunId?: number;
|
|
26
|
-
};
|
|
27
|
-
};
|
|
28
|
-
export default class ResultsParser {
|
|
29
|
-
private result;
|
|
30
|
-
constructor();
|
|
31
|
-
getParsedResults(): Promise<SummaryResults>;
|
|
32
|
-
getFailures(): Promise<Array<failure>>;
|
|
33
|
-
static getTestName(failedTest: any): any;
|
|
34
|
-
updateResults(data: {
|
|
35
|
-
testSuite: any;
|
|
36
|
-
}): void;
|
|
37
|
-
addTestResult(suiteName: any, testCase: any): void;
|
|
38
|
-
safelyDetermineFailure(result: {
|
|
39
|
-
errors: any[];
|
|
40
|
-
error: {
|
|
41
|
-
message: string;
|
|
42
|
-
stack: string;
|
|
43
|
-
};
|
|
44
|
-
}): string;
|
|
45
|
-
cleanseReason(rawReaseon: string): string;
|
|
46
|
-
}
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { failure, SummaryResults } from '.';
|
|
3
|
+
export declare type testResult = {
|
|
4
|
+
suiteName: string;
|
|
5
|
+
name: string;
|
|
6
|
+
browser?: string;
|
|
7
|
+
projectName: string;
|
|
8
|
+
endedAt: string;
|
|
9
|
+
reason: string;
|
|
10
|
+
retry: number;
|
|
11
|
+
retries: number;
|
|
12
|
+
startedAt: string;
|
|
13
|
+
status: 'passed' | 'failed' | 'timedOut' | 'skipped';
|
|
14
|
+
attachments?: {
|
|
15
|
+
body: string | undefined | Buffer;
|
|
16
|
+
contentType: string;
|
|
17
|
+
name: string;
|
|
18
|
+
path: string;
|
|
19
|
+
}[];
|
|
20
|
+
};
|
|
21
|
+
export declare type testSuite = {
|
|
22
|
+
testSuite: {
|
|
23
|
+
title: string;
|
|
24
|
+
tests: testResult[];
|
|
25
|
+
testRunId?: number;
|
|
26
|
+
};
|
|
27
|
+
};
|
|
28
|
+
export default class ResultsParser {
|
|
29
|
+
private result;
|
|
30
|
+
constructor();
|
|
31
|
+
getParsedResults(): Promise<SummaryResults>;
|
|
32
|
+
getFailures(): Promise<Array<failure>>;
|
|
33
|
+
static getTestName(failedTest: any): any;
|
|
34
|
+
updateResults(data: {
|
|
35
|
+
testSuite: any;
|
|
36
|
+
}): void;
|
|
37
|
+
addTestResult(suiteName: any, testCase: any): void;
|
|
38
|
+
safelyDetermineFailure(result: {
|
|
39
|
+
errors: any[];
|
|
40
|
+
error: {
|
|
41
|
+
message: string;
|
|
42
|
+
stack: string;
|
|
43
|
+
};
|
|
44
|
+
}): string;
|
|
45
|
+
cleanseReason(rawReaseon: string): string;
|
|
46
|
+
}
|