playwright-slack-report 1.1.3 → 1.1.15

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 CHANGED
@@ -128,7 +128,9 @@ An example advanced configuration is shown below:
128
128
  },
129
129
  ],
130
130
  slackOAuthToken: 'YOUR_SLACK_OAUTH_TOKEN',
131
- slackLogLevel: LogLevel.DEBUG
131
+ slackLogLevel: LogLevel.DEBUG,
132
+ enableUnfurl: false,
133
+ showInThread: true,
132
134
  },
133
135
 
134
136
  ],
@@ -153,7 +155,15 @@ Limits the number of failures shown in the Slack message, defaults to 10.
153
155
  Instead of providing an environment variable `SLACK_BOT_USER_OAUTH_TOKEN` you can specify the token in the config in the `slackOAuthToken` field.
154
156
  ### **slackLogLevel** (default LogLevel.DEBUG)
155
157
  This option allows you to control slack client severity levels for log entries. It accepts a value from @slack/web-api `LogLevel` enum
158
+ ### **enableUnfurl** (default: true)
159
+ Enable or disable unfurling of links in Slack messages.
160
+ ### **showInThread** (default: false)
161
+ Instructs the reporter to show the failure details in a thread instead of the main channel.
156
162
 
163
+ ![Show failures in threads](./assets/threads.png)
164
+
165
+ ### **meta** (default: empty array)
166
+ The meta data to be sent to Slack. This is useful for providing additional context to your test run.
157
167
 
158
168
  **Examples:**
159
169
  ```typescript
@@ -530,7 +540,7 @@ Run the tests using `npm run pw`
530
540
  Run `npm pack`
531
541
 
532
542
  Create a new playwright project using `yarn create playwright`
533
- Modify the `package.json` and a local dependancy to the generated `tgz` file
543
+ Modify the `package.json` and a local dependency to the generated `tgz` file
534
544
 
535
545
  e.g.
536
546
 
@@ -1,4 +1,5 @@
1
1
  import { KnownBlock, Block } from '@slack/types';
2
2
  import { SummaryResults } from '.';
3
3
  declare const generateBlocks: (summaryResults: SummaryResults, maxNumberOfFailures: number) => Promise<Array<KnownBlock | Block>>;
4
- export default generateBlocks;
4
+ declare const generateFailures: (summaryResults: SummaryResults, maxNumberOfFailures: number) => Promise<Array<KnownBlock | Block>>;
5
+ export { generateBlocks, generateFailures };
@@ -1,5 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
+ exports.generateFailures = exports.generateBlocks = void 0;
3
4
  const generateBlocks = async (summaryResults, maxNumberOfFailures) => {
4
5
  const maxNumberOfFailureLength = 650;
5
6
  const fails = [];
@@ -66,4 +67,41 @@ const generateBlocks = async (summaryResults, maxNumberOfFailures) => {
66
67
  ...fails,
67
68
  ];
68
69
  };
69
- exports.default = generateBlocks;
70
+ exports.generateBlocks = generateBlocks;
71
+ const generateFailures = async (summaryResults, maxNumberOfFailures) => {
72
+ const maxNumberOfFailureLength = 650;
73
+ const fails = [];
74
+ for (let i = 0; i < summaryResults.failures.length; i += 1) {
75
+ const { failureReason, test } = summaryResults.failures[i];
76
+ const formattedFailure = failureReason
77
+ .substring(0, maxNumberOfFailureLength)
78
+ .split('\n')
79
+ .map((l) => `>${l}`)
80
+ .join('\n');
81
+ fails.push({
82
+ type: 'section',
83
+ text: {
84
+ type: 'mrkdwn',
85
+ text: `*${test}*
86
+ \n${formattedFailure}`,
87
+ },
88
+ });
89
+ if (i > maxNumberOfFailures) {
90
+ fails.push({
91
+ type: 'section',
92
+ text: {
93
+ type: 'mrkdwn',
94
+ text: `*There are too many failures to display - ${fails.length} out of ${summaryResults.failures.length} failures shown*`,
95
+ },
96
+ });
97
+ break;
98
+ }
99
+ }
100
+ return [
101
+ {
102
+ type: 'divider',
103
+ },
104
+ ...fails,
105
+ ];
106
+ };
107
+ exports.generateFailures = generateFailures;
@@ -16,11 +16,22 @@ export default class SlackClient {
16
16
  maxNumberOfFailures: number;
17
17
  slackOAuthToken?: string;
18
18
  slackLogLevel?: LogLevel;
19
+ unfurlEnable?: boolean;
19
20
  summaryResults: SummaryResults;
21
+ showInThread: boolean;
20
22
  };
21
23
  }): Promise<Array<{
22
24
  channel: string;
23
25
  outcome: string;
26
+ ts: string;
24
27
  }>>;
25
- doPostRequest(channel: string, blocks: Array<KnownBlock | Block>): Promise<ChatPostMessageResponse>;
28
+ attachDetailsToThread({ channelIds, ts, summaryResults, maxNumberOfFailures, unfurlEnable, fakeRequest, }: {
29
+ channelIds: Array<string>;
30
+ ts: string;
31
+ summaryResults: SummaryResults;
32
+ maxNumberOfFailures: number;
33
+ unfurlEnable?: boolean;
34
+ fakeRequest?: Function;
35
+ }): Promise<any[]>;
36
+ static doPostRequest(slackWebClient: WebClient, channel: string, blocks: Array<KnownBlock | Block>, unfurl: boolean, threadTimestamp?: string): Promise<ChatPostMessageResponse>;
26
37
  }
@@ -14,13 +14,19 @@ class SlackClient {
14
14
  else if (options.customLayoutAsync) {
15
15
  blocks = await options.customLayoutAsync(options.summaryResults);
16
16
  }
17
+ else if (options.showInThread) {
18
+ const modifiedOptions = JSON.parse(JSON.stringify(options));
19
+ modifiedOptions.summaryResults.failures = [];
20
+ blocks = await (0, LayoutGenerator_1.generateBlocks)(modifiedOptions.summaryResults, options.maxNumberOfFailures);
21
+ }
17
22
  else {
18
- blocks = await (0, LayoutGenerator_1.default)(options.summaryResults, options.maxNumberOfFailures);
23
+ blocks = await (0, LayoutGenerator_1.generateBlocks)(options.summaryResults, options.maxNumberOfFailures);
19
24
  }
20
25
  if (!options.channelIds) {
21
26
  throw new Error(`Channel ids [${options.channelIds}] is not valid`);
22
27
  }
23
28
  const result = [];
29
+ const unfurl = options.unfurlEnable;
24
30
  for (const channel of options.channelIds) {
25
31
  let chatResponse;
26
32
  try {
@@ -30,15 +36,22 @@ class SlackClient {
30
36
  }
31
37
  else {
32
38
  // send request for reals
33
- chatResponse = await this.doPostRequest(channel, blocks);
39
+ chatResponse = await SlackClient.doPostRequest(this.slackWebClient, channel, blocks, unfurl);
34
40
  }
35
41
  if (chatResponse.ok) {
36
- result.push({ channel, outcome: `✅ Message sent to ${channel}` });
42
+ result.push({
43
+ channel,
44
+ outcome: `✅ Message sent to ${channel}`,
45
+ ts: chatResponse.ts,
46
+ });
37
47
  // eslint-disable-next-line no-console
38
48
  console.log(`✅ Message sent to ${channel}`);
39
49
  }
40
50
  else {
41
- result.push({ channel, outcome: `❌ Message not sent to ${channel} \r\n ${JSON.stringify(chatResponse, null, 2)}` });
51
+ result.push({
52
+ channel,
53
+ outcome: `❌ Message not sent to ${channel} \r\n ${JSON.stringify(chatResponse, null, 2)}`,
54
+ });
42
55
  }
43
56
  }
44
57
  catch (error) {
@@ -50,11 +63,37 @@ class SlackClient {
50
63
  }
51
64
  return result;
52
65
  }
53
- async doPostRequest(channel, blocks) {
54
- const chatResponse = await this.slackWebClient.chat.postMessage({
66
+ async attachDetailsToThread({ channelIds, ts, summaryResults, maxNumberOfFailures, unfurlEnable, fakeRequest, }) {
67
+ const result = [];
68
+ const blocks = await (0, LayoutGenerator_1.generateFailures)(summaryResults, maxNumberOfFailures);
69
+ for (const channel of channelIds) {
70
+ // under test
71
+ let chatResponse;
72
+ if (fakeRequest) {
73
+ chatResponse = await fakeRequest();
74
+ }
75
+ else {
76
+ chatResponse = await SlackClient.doPostRequest(this.slackWebClient, channel, blocks, unfurlEnable, ts);
77
+ }
78
+ if (chatResponse.ok) {
79
+ // eslint-disable-next-line no-console
80
+ console.log(`✅ Message sent to ${channel} within thread ${ts}`);
81
+ result.push({
82
+ channel,
83
+ outcome: `✅ Message sent to ${channel} within thread ${ts}`,
84
+ ts: chatResponse.ts,
85
+ });
86
+ }
87
+ }
88
+ return result;
89
+ }
90
+ static async doPostRequest(slackWebClient, channel, blocks, unfurl, threadTimestamp) {
91
+ const chatResponse = await slackWebClient.chat.postMessage({
55
92
  channel,
56
93
  text: ' ',
94
+ unfurl_link: unfurl,
57
95
  blocks,
96
+ thread_ts: threadTimestamp,
58
97
  });
59
98
  return chatResponse;
60
99
  }
@@ -3,12 +3,14 @@ declare class SlackReporter implements Reporter {
3
3
  private customLayout;
4
4
  private customLayoutAsync;
5
5
  private maxNumberOfFailuresToShow;
6
+ private showInThread;
6
7
  private meta;
7
8
  private resultsParser;
8
9
  private sendResults;
9
10
  private slackChannels;
10
11
  private slackLogLevel;
11
12
  private slackOAuthToken;
13
+ private enableUnfurl;
12
14
  private suite;
13
15
  logs: string[];
14
16
  onBegin(fullConfig: FullConfig, suite: Suite): void;
@@ -7,12 +7,14 @@ class SlackReporter {
7
7
  customLayout;
8
8
  customLayoutAsync;
9
9
  maxNumberOfFailuresToShow;
10
+ showInThread;
10
11
  meta = [];
11
12
  resultsParser;
12
13
  sendResults = 'on-failure';
13
14
  slackChannels = [];
14
15
  slackLogLevel;
15
16
  slackOAuthToken;
17
+ enableUnfurl;
16
18
  suite;
17
19
  logs = [];
18
20
  onBegin(fullConfig, suite) {
@@ -27,6 +29,8 @@ class SlackReporter {
27
29
  this.slackChannels = slackReporterConfig.channels;
28
30
  this.maxNumberOfFailuresToShow = slackReporterConfig.maxNumberOfFailuresToShow || 10;
29
31
  this.slackOAuthToken = slackReporterConfig.slackOAuthToken || undefined;
32
+ this.enableUnfurl = slackReporterConfig.enableUnfurl || true;
33
+ this.showInThread = slackReporterConfig.showInThread || false;
30
34
  }
31
35
  this.resultsParser = new ResultsParser_1.default();
32
36
  }
@@ -44,7 +48,8 @@ class SlackReporter {
44
48
  resultSummary.meta = this.meta;
45
49
  const maxRetry = Math.max(...resultSummary.tests.map((o) => o.retry));
46
50
  if (this.sendResults === 'on-failure'
47
- && resultSummary.tests.filter((z) => (z.status === 'failed' || z.status === 'timedOut') && z.retry === maxRetry).length === 0) {
51
+ && resultSummary.tests.filter((z) => (z.status === 'failed' || z.status === 'timedOut')
52
+ && z.retry === maxRetry).length === 0) {
48
53
  this.log('⏩ Slack reporter - no failures found');
49
54
  return;
50
55
  }
@@ -57,11 +62,21 @@ class SlackReporter {
57
62
  customLayout: this.customLayout,
58
63
  customLayoutAsync: this.customLayoutAsync,
59
64
  maxNumberOfFailures: this.maxNumberOfFailuresToShow,
65
+ unfurlEnable: this.enableUnfurl,
60
66
  summaryResults: resultSummary,
67
+ showInThread: this.showInThread,
61
68
  },
62
69
  });
63
70
  // eslint-disable-next-line no-console
64
71
  console.log(JSON.stringify(result, null, 2));
72
+ if (this.showInThread && resultSummary.failures.length > 0) {
73
+ await slackClient.attachDetailsToThread({
74
+ channelIds: this.slackChannels,
75
+ ts: result[0].ts,
76
+ summaryResults: resultSummary,
77
+ maxNumberOfFailures: this.maxNumberOfFailuresToShow,
78
+ });
79
+ }
65
80
  }
66
81
  preChecks() {
67
82
  if (this.sendResults === 'off') {
package/package.json CHANGED
@@ -28,7 +28,7 @@
28
28
  "lint":"npx eslint . --ext .ts"
29
29
  },
30
30
  "name": "playwright-slack-report",
31
- "version": "1.1.3",
31
+ "version": "1.1.15",
32
32
  "main": "index.js",
33
33
  "types": "dist/index.d.ts",
34
34
  "repository": "git@github.com:ryanrosello-og/playwright-slack-report.git",