playwright-slack-report-burak 1.2.2 → 1.2.4

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.
@@ -2,4 +2,5 @@ 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
4
  declare const generateFailures: (summaryResults: SummaryResults, maxNumberOfFailures: number) => Promise<Array<KnownBlock | Block>>;
5
- export { generateBlocks, generateFailures };
5
+ declare const generateFailuresReasons: (summaryResults: SummaryResults, maxNumberOfFailures: number) => Promise<Array<KnownBlock | Block>>;
6
+ export { generateBlocks, generateFailures, generateFailuresReasons };
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.generateFailures = exports.generateSkippers = exports.generateBlocks = void 0;
3
+ exports.generateFailures = exports.generateFailuresReasons = exports.generateBlocks = void 0;
4
4
  const generateBlocks = async (summaryResults, maxNumberOfFailures) => {
5
5
  const meta = [];
6
6
  const header = {
@@ -35,34 +35,189 @@ const generateBlocks = async (summaryResults, maxNumberOfFailures) => {
35
35
  return [header, summary, ...meta, ...fails];
36
36
  };
37
37
  exports.generateBlocks = generateBlocks;
38
- const generateFailures = async (summaryResults, maxNumberOfFailures) => {
39
- const maxNumberOfFailureLength = 650;
40
- const fails = [];
41
- const numberOfFailuresToShow = Math.min(summaryResults.failures.length, maxNumberOfFailures);
42
- for (let i = 0; i < numberOfFailuresToShow; i += 1) {
43
- const { failureReason, test } = summaryResults.failures[i];
44
- const formattedFailure = failureReason
45
- .substring(0, maxNumberOfFailureLength)
46
- .split('\n')[0];
47
- fails.push({
48
- type: 'section',
49
- text: {
50
- type: 'mrkdwn',
51
- text: `*${test.split(' [')[0]}*\n${formattedFailure}`,
52
- },
53
- });
38
+
39
+ /*
40
+ Currently unused but can be used to move failed test name list from main
41
+ message to thread when there are too many for the main message.
42
+ */
43
+ const generateFailures = async (summaryResults) => {
44
+ const thread = [];
45
+ const failedNamesTitle = [];
46
+ const skippedNamesTitle = [];
47
+ const failsList = [];
48
+ const skipsList = [];
49
+ let previousTestName = undefined;
50
+ let previousSuiteName = undefined;
51
+
52
+ // Create a list for names of failed test cases
53
+ for (const result of summaryResults.tests) {
54
+ if (result.status === 'failed' || result.status === 'timedOut') {
55
+ const testName = result.name;
56
+ const suiteName = result.suiteName;
57
+ const parts = result.suiteName.split('/')[result.suiteName.split('/').length-1].replace('.spec.ts', '');
58
+ const backSlashedParts = parts.split('\\')[parts.split('\\').length-1];
59
+ if (testName !== previousTestName || (testName === previousSuiteName && suiteName !== previousSuiteName) ) {
60
+ failsList.push(testName + ' (' + backSlashedParts + ')');
61
+ previousTestName = testName;
62
+ previousSuiteName = suiteName;
63
+ }
64
+ }
65
+ }
66
+ previousTestName = undefined;
67
+ previousSuiteName = undefined;
68
+
69
+ // Create a list for names of skipped test cases
70
+ for (const result of summaryResults.tests) {
71
+ if (result.status === 'skipped') {
72
+ const testName = result.name;
73
+ const suiteName = result.suiteName;
74
+ const parts = result.suiteName.split('/')[result.suiteName.split('/').length-1].replace('.spec.ts', '');
75
+ const backSlashedParts = parts.split('\\')[parts.split('\\').length-1];
76
+ if (testName !== previousTestName || (testName === previousSuiteName && suiteName !== previousSuiteName) ) {
77
+ skipsList.push(testName + ' (' + backSlashedParts + ')');
78
+ previousTestName = testName;
79
+ previousSuiteName = suiteName;
80
+ }
81
+ }
82
+ }
83
+ previousTestName = undefined;
84
+ previousSuiteName = undefined;
85
+
86
+ // Decide on Titles For Listing Failures & Skips
87
+ if (summaryResults.failed === 1) {
88
+ failedNamesTitle[0] = '\n*Failed Test Case:*\n';
89
+ }
90
+ if (summaryResults.failed > 1) {
91
+ failedNamesTitle[0] = '\n*Failed Test Cases:*\n';
92
+ }
93
+ if (summaryResults.skipped === 1) {
94
+ skippedNamesTitle[0] = '\n*Skipped Test Case:*\n';
95
+ }
96
+ if (summaryResults.skipped > 1) {
97
+ skippedNamesTitle[0] = '\n*Skipped Test Cases:*\n';
98
+ }
99
+
100
+ thread.push({
101
+ type: 'section',
102
+ text: {
103
+ type: 'mrkdwn',
104
+ text: `${failedNamesTitle}${failsList.map((value, index) => `*${index + 1}.* ${value}`).join('\n')}` + // List of Failed Test Cases
105
+ `\n${skippedNamesTitle}${skipsList.map((value, index) => `*${index + 1}.* ${value}`).join('\n')} `, // List of Skipped Test Cases
106
+ },
107
+ })
108
+ return [
109
+ ...thread,
110
+ ];
111
+ };
112
+
113
+ const generateFailuresReasons = async (summaryResults) => {
114
+ const failedNamesTitle = [];
115
+ const failsList = [];
116
+
117
+ for (let i = 0; i <= summaryResults.failures.length; i += 1) {
118
+ if (summaryResults.failures.length <=3) {
119
+ if (i === summaryResults.failures.length) {
120
+ break;
121
+ }
122
+ const { failureReason, test, suiteName } = summaryResults.failures[i];
123
+ const parts = suiteName.split('/')[suiteName.split('/').length-1].replace('.spec.ts', '');
124
+ const backSlashedParts = parts.split('\\')[parts.split('\\').length-1];
125
+ failsList.push({
126
+ type: 'section',
127
+ text: {
128
+ type: 'mrkdwn',
129
+ text: `${i+1}. ${test.split(' [')[0]} (${backSlashedParts})\n\`\`\`${failureReason}\`\`\``,
130
+ },
131
+ });
132
+ } else if (3 < summaryResults.failures.length < 25) {
133
+ const { failureReason, test, suiteName } = summaryResults.failures[i];
134
+ const parts = suiteName.split('/')[suiteName.split('/').length-1].replace('.spec.ts', '');
135
+ const backSlashedParts = parts.split('\\')[parts.split('\\').length-1];
136
+ failsList.push({
137
+ type: 'section',
138
+ text: {
139
+ type: 'mrkdwn',
140
+ text: `${i+1}. ${test.split(' [')[0]} (${backSlashedParts})\n\`\`\`${failureReason.split('\n')[0]}\`\`\``,
141
+ },
142
+ });
143
+ if (i === summaryResults.failures.length) {
144
+ fails.push({
145
+ type: 'section',
146
+ text: {
147
+ type: 'mrkdwn',
148
+ text: '⚠️ *There are too many failures to display in full detail. '+
149
+ 'You can view more on CircleCI* ⚠️',
150
+ },
151
+ },
152
+ {
153
+ type: 'actions',
154
+ elements: [
155
+ {
156
+ type: 'button',
157
+ text: {
158
+ type: 'plain_text',
159
+ text: 'Go to Build Details'
160
+ },
161
+ url: process.env.CIRCLE_BUILD_URL
162
+ }
163
+ ]
164
+ });
165
+ }
166
+ } else if (summaryResults.failures.length >= 25) {
167
+ const { failureReason, test, suiteName } = summaryResults.failures[i];
168
+ const parts = suiteName.split('/')[suiteName.split('/').length-1].replace('.spec.ts', '');
169
+ const backSlashedParts = parts.split('\\')[parts.split('\\').length-1];
170
+ failsList.push({
171
+ type: 'section',
172
+ text: {
173
+ type: 'mrkdwn',
174
+ text: `${i+1}. ${test.split(' [')[0]} (${backSlashedParts})\n\`\`\`${failureReason.split('\n')[0]}\`\`\``,
175
+ },
176
+ });
177
+ if (i > 24) {
178
+ fails.push({
179
+ type: 'section',
180
+ text: {
181
+ type: 'mrkdwn',
182
+ text: '⚠️ *There are too many failures to display here '+
183
+ 'You can view more on CircleCI* ⚠️',
184
+ },
185
+ },
186
+ {
187
+ type: 'actions',
188
+ elements: [
189
+ {
190
+ type: 'button',
191
+ text: {
192
+ type: 'plain_text',
193
+ text: 'Go to Build Details'
194
+ },
195
+ url: process.env.CIRCLE_BUILD_URL
196
+ }
197
+ ]
198
+ });
199
+ }
200
+ }
54
201
  }
55
- if (summaryResults.failures.length > maxNumberOfFailures) {
56
- fails.push({
57
- type: 'section',
58
- text: {
59
- type: 'mrkdwn',
60
- text: `*⚠️ There are too many failures to display - ${fails.length} out of ${summaryResults.failures.length} failures shown*`,
61
- },
62
- });
202
+
203
+ // Decide on Titles For Listing Failures & Skips
204
+ if (summaryResults.failed === 1) {
205
+ failedNamesTitle[0] = '\n*Failure Reason:*\n';
63
206
  }
207
+ if (summaryResults.failed > 1) {
208
+ failedNamesTitle[0] = '\n*Failure Reasons:*\n';
209
+ }
210
+
211
+ failsList.unshift({
212
+ type: 'section',
213
+ text: {
214
+ type: 'mrkdwn',
215
+ text: `${failedNamesTitle}`
216
+ },
217
+ })
64
218
  return [
65
- ...fails,
219
+ ...failsList,
66
220
  ];
67
221
  };
68
- exports.generateFailures = generateFailures;
222
+ exports.generateFailures = generateFailures;
223
+ exports.generateFailuresReasons = generateFailuresReasons;
@@ -1,5 +1,5 @@
1
1
  /// <reference types="node" />
2
- import { failure, flaky, pass, skipper, SummaryResults } from '.';
2
+ import { failure, flaky, pass, SummaryResults } from '.';
3
3
  export declare type testResult = {
4
4
  suiteName: string;
5
5
  name: string;
@@ -35,8 +35,7 @@ export default class ResultsParser {
35
35
  getFailures(): Promise<Array<failure>>;
36
36
  getFlakes(): Promise<Array<flaky>>;
37
37
  getPasses(): Promise<Array<pass>>;
38
- getSkippers(): Promise<Array<skipper>>;
39
- static getTestName(failedTest: any): any;
38
+ static getTestName(failedTest: any): any;
40
39
  updateResults(data: {
41
40
  testSuite: any;
42
41
  }): void;
@@ -17,7 +17,6 @@ class ResultsParser {
17
17
  const failures = await this.getFailures();
18
18
  const flakes = await this.getFlakes();
19
19
  let passes = await this.getPasses();
20
- const skippers = await this.getSkippers();
21
20
  /*if (this.separateFlakyTests) {
22
21
  passes = this.doSeparateFlakyTests(passes, flakes);
23
22
  }*/
@@ -26,16 +25,16 @@ class ResultsParser {
26
25
  failed: failures.length,
27
26
  flaky: (this.separateFlakyTests && flakes.length > 0) ?
28
27
  flakes.length : 0,
29
- skipped: skippers.length,
28
+ skipped: 0,
30
29
  failures,
31
30
  tests: [],
32
31
  };
33
32
  for (const suite of this.result) {
34
33
  summary.tests = summary.tests.concat(suite.testSuite.tests);
35
34
  for (const test of suite.testSuite.tests) {
36
- /*if (test.status === 'skipped') {
35
+ if (test.status === 'skipped') {
37
36
  summary.skipped += 1;
38
- }*/
37
+ }
39
38
  }
40
39
  }
41
40
  return summary;
@@ -63,7 +62,7 @@ class ResultsParser {
63
62
  const flaky = [];
64
63
  for (const suite of this.result) {
65
64
  for (const test of suite.testSuite.tests) {
66
- if (test.status === 'passed' && test.retry > 0) {
65
+ if (this.separateFlakyTests && test.status === 'passed' && test.retry > 0) {
67
66
  flaky.push({
68
67
  test: ResultsParser.getTestName(test),
69
68
  retry: test.retry,
@@ -77,31 +76,23 @@ class ResultsParser {
77
76
  const passes = [];
78
77
  for (const suite of this.result) {
79
78
  for (const test of suite.testSuite.tests) {
80
- if (test.status === 'passed' && test.retry === 0) {
81
- passes.push({
82
- test: ResultsParser.getTestName(test),
83
- });
79
+ if (this.separateFlakyTests) {
80
+ if (test.status === 'passed' && test.retry === 0) {
81
+ passes.push({
82
+ test: ResultsParser.getTestName(test),
83
+ });
84
+ }
85
+ } else {
86
+ if (test.status === 'passed') {
87
+ passes.push({
88
+ test: ResultsParser.getTestName(test),
89
+ });
90
+ }
84
91
  }
85
92
  }
86
93
  }
87
94
  return passes;
88
95
  }
89
-
90
- async getSkippers() {
91
- const skippers = [];
92
- for (const suite of this.result) {
93
- for (const test of suite.testSuite.tests) {
94
- if (test.status === 'skipped') {
95
- skippers.push({
96
- test: ResultsParser.getTestName(test),
97
- });
98
- }
99
- }
100
- }
101
- return skippers;
102
- }
103
-
104
-
105
96
  static getTestName(failedTest) {
106
97
  const testName = failedTest.name;
107
98
  if (failedTest.browser && failedTest.projectName) {
@@ -176,7 +167,9 @@ class ResultsParser {
176
167
  }
177
168
  /** removes tests from the passed array that only passed on a retry (flaky).
178
169
  * Does not modify param passed, returns a new passed array. */
179
- doSeparateFlakyTests(passes, flakes) {
170
+ /** Cuurently unused. Instead, we check the seperateflaky flag while
171
+ * passed array. */
172
+ /*doSeparateFlakyTests(passes, flakes) {
180
173
  const _passes = new Map();
181
174
  for (const pass of passes) {
182
175
  _passes.set(pass.test, pass);
@@ -185,6 +178,6 @@ class ResultsParser {
185
178
  _passes.delete(flake.test);
186
179
  }
187
180
  return [..._passes.values()];
188
- }
181
+ }*/
189
182
  }
190
183
  exports.default = ResultsParser;
@@ -33,5 +33,13 @@ export default class SlackClient {
33
33
  disableUnfurl?: boolean;
34
34
  fakeRequest?: Function;
35
35
  }): Promise<any[]>;
36
+ attachDetailsToThreadReasons({ channelIds, ts, summaryResults, maxNumberOfFailures, disableUnfurl, fakeRequest, }: {
37
+ channelIds: Array<string>;
38
+ ts: string;
39
+ summaryResults: SummaryResults;
40
+ maxNumberOfFailures: number;
41
+ disableUnfurl?: boolean;
42
+ fakeRequest?: Function;
43
+ }): Promise<any[]>;
36
44
  static doPostRequest(slackWebClient: WebClient, channel: string, blocks: Array<KnownBlock | Block>, unfurl: boolean, threadTimestamp?: string): Promise<ChatPostMessageResponse>;
37
45
  }
@@ -87,6 +87,30 @@ class SlackClient {
87
87
  }
88
88
  return result;
89
89
  }
90
+ async attachDetailsToThreadReasons({ channelIds, ts, summaryResults, maxNumberOfFailures, disableUnfurl, fakeRequest, }) {
91
+ const result = [];
92
+ const blocks = await (0, LayoutGenerator_1.generateFailuresReasons)(summaryResults, maxNumberOfFailures);
93
+ for (const channel of channelIds) {
94
+ // under test
95
+ let chatResponse;
96
+ if (fakeRequest) {
97
+ chatResponse = await fakeRequest();
98
+ }
99
+ else {
100
+ chatResponse = await SlackClient.doPostRequest(this.slackWebClient, channel, blocks, disableUnfurl, ts);
101
+ }
102
+ if (chatResponse.ok) {
103
+ // eslint-disable-next-line no-console
104
+ console.log(`✅ Message sent to ${channel} within thread ${ts}`);
105
+ result.push({
106
+ channel,
107
+ outcome: `✅ Message sent to ${channel} within thread ${ts}`,
108
+ ts: chatResponse.ts,
109
+ });
110
+ }
111
+ }
112
+ return result;
113
+ }
90
114
  static async doPostRequest(slackWebClient, channel, blocks, unfurl, threadTimestamp) {
91
115
  const chatResponse = await slackWebClient.chat.postMessage({
92
116
  channel,
@@ -111,8 +111,8 @@ class SlackReporter {
111
111
  });
112
112
  // eslint-disable-next-line no-console
113
113
  console.log(JSON.stringify(result, null, 2));
114
- if (this.showInThread && resultSummary.failures.length > 0) {
115
- for (let i = 0; i < result.length; i += 1) {
114
+ if (this.showInThread && (resultSummary.failures.length > 0 || resultSummary.skipped > 0)) {
115
+ /* for (let i = 0; i < result.length; i += 1) {
116
116
  // eslint-disable-next-line no-await-in-loop
117
117
  await slackClient.attachDetailsToThread({
118
118
  channelIds: [result[i].channel],
@@ -120,6 +120,15 @@ class SlackReporter {
120
120
  summaryResults: resultSummary,
121
121
  maxNumberOfFailures: this.maxNumberOfFailuresToShow,
122
122
  });
123
+ }*/
124
+ for (let i = 0; i < result.length; i += 1) {
125
+ // eslint-disable-next-line no-await-in-loop
126
+ await slackClient.attachDetailsToThreadReasons({
127
+ channelIds: [result[i].channel],
128
+ ts: result[i].ts,
129
+ summaryResults: resultSummary,
130
+ maxNumberOfFailures: this.maxNumberOfFailuresToShow,
131
+ });
123
132
  }
124
133
  }
125
134
  }
@@ -2,11 +2,9 @@
2
2
  export declare type SummaryResults = {
3
3
  passed: number;
4
4
  failed: number;
5
- flaky: number | undefined;
5
+ flaky: number;
6
6
  skipped: number;
7
7
  failures: Array<failure>;
8
- skippers: Array<skipper>;
9
- flakers: Array<flaker>;
10
8
  meta?: Array<{
11
9
  key: string;
12
10
  value: string;
@@ -32,23 +30,13 @@ export declare type SummaryResults = {
32
30
  export declare type failure = {
33
31
  test: string;
34
32
  failureReason: string;
33
+ retries: number;
34
+ suiteName: string;
35
35
  };
36
-
37
- export declare type skipper = {
38
- test: string;
39
- skipperReason: string;
40
- };
41
-
42
- export declare type flaker = {
43
- test: string;
44
- flakerReason: string;
45
- };
46
-
47
36
  export declare type flaky = {
48
37
  test: string;
49
38
  retry: number;
50
39
  };
51
-
52
40
  export declare type pass = {
53
41
  test: string;
54
42
  };
package/package.json CHANGED
@@ -30,7 +30,7 @@
30
30
  "lint-fix": "npx eslint . --ext .ts --fix"
31
31
  },
32
32
  "name": "playwright-slack-report-burak",
33
- "version": "1.2.2",
33
+ "version": "1.2.4",
34
34
  "main": "index.js",
35
35
  "types": "dist/index.d.ts",
36
36
  "repository": "git@github.com:ryanrosello-og/playwright-slack-report.git",