cypress-qase-reporter 3.1.0 → 3.1.2

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/changelog.md CHANGED
@@ -1,3 +1,15 @@
1
+ # cypress-qase-reporter@3.1.2
2
+
3
+ ## What's new
4
+
5
+ - Improved handling of skipped tests due to failing beforeEach hooks.
6
+
7
+ # cypress-qase-reporter@3.1.1
8
+
9
+ ## What's new
10
+
11
+ - Fixed an issue where the reporter was not reporting skipped tests due to failing beforeEach hooks.
12
+
1
13
  # cypress-qase-reporter@3.1.0
2
14
 
3
15
  ## What's new
@@ -35,6 +35,12 @@ export declare class CypressQaseReporter extends reporters.Base {
35
35
  */
36
36
  private reporter;
37
37
  private testBeginTime;
38
+ /**
39
+ * Set to track processed tests to identify skipped tests when beforeEach fails
40
+ * @type {Set<string>}
41
+ * @private
42
+ */
43
+ private processedTests;
38
44
  /**
39
45
  * @param {Runner} runner
40
46
  * @param {CypressQaseOptionsType} options
@@ -46,6 +52,45 @@ export declare class CypressQaseReporter extends reporters.Base {
46
52
  * @private
47
53
  */
48
54
  private addRunnerListeners;
55
+ /**
56
+ * Generate a unique identifier for a test
57
+ * @param {Test} test
58
+ * @returns {string}
59
+ * @private
60
+ */
61
+ private getTestIdentifier;
62
+ /**
63
+ * Mark a test as processed
64
+ * @param {Test} test
65
+ * @private
66
+ */
67
+ private markTestAsProcessed;
68
+ /**
69
+ * Check if a test was processed
70
+ * @param {Test} test
71
+ * @returns {boolean}
72
+ * @private
73
+ */
74
+ private isTestProcessed;
75
+ /**
76
+ * Handle skipped tests in a suite when beforeEach hook fails
77
+ * @param {Suite} suite
78
+ * @private
79
+ */
80
+ /**
81
+ * Recursively collect all tests from a suite and its nested suites
82
+ * @param {Suite} suite
83
+ * @param {Test[]} tests
84
+ * @private
85
+ */
86
+ private collectAllTestsFromSuite;
87
+ private handleSkippedTestsInSuite;
88
+ /**
89
+ * Add a test result for a skipped test (due to beforeEach failure)
90
+ * @param {Test} test
91
+ * @private
92
+ */
93
+ private addSkippedTestResult;
49
94
  /**
50
95
  * @param {Test} test
51
96
  * @private
package/dist/reporter.js CHANGED
@@ -14,7 +14,7 @@ const manager_1 = require("./metadata/manager");
14
14
  const fileSearcher_1 = require("./fileSearcher");
15
15
  const tagParser_1 = require("./utils/tagParser");
16
16
  const resultsManager_1 = require("./metadata/resultsManager");
17
- const { EVENT_TEST_FAIL, EVENT_TEST_PASS, EVENT_TEST_PENDING, EVENT_RUN_END, EVENT_TEST_BEGIN, } = mocha_1.Runner.constants;
17
+ const { EVENT_TEST_FAIL, EVENT_TEST_PASS, EVENT_TEST_PENDING, EVENT_RUN_END, EVENT_TEST_BEGIN, EVENT_SUITE_END } = mocha_1.Runner.constants;
18
18
  /**
19
19
  * @class CypressQaseReporter
20
20
  * @extends reporters.Base
@@ -57,6 +57,12 @@ class CypressQaseReporter extends mocha_1.reporters.Base {
57
57
  */
58
58
  reporter;
59
59
  testBeginTime = Date.now();
60
+ /**
61
+ * Set to track processed tests to identify skipped tests when beforeEach fails
62
+ * @type {Set<string>}
63
+ * @private
64
+ */
65
+ processedTests = new Set();
60
66
  // private options: Omit<(FrameworkOptionsType<'cypress', ReporterOptionsType> & ConfigType & ReporterOptionsType & NonNullable<unknown>) | (null & ReporterOptionsType & NonNullable<unknown>), 'framework'>;
61
67
  /**
62
68
  * @param {Runner} runner
@@ -84,26 +90,178 @@ class CypressQaseReporter extends mocha_1.reporters.Base {
84
90
  * @private
85
91
  */
86
92
  addRunnerListeners(runner) {
87
- runner.on(EVENT_TEST_PASS, (test) => this.addTestResult(test));
88
- runner.on(EVENT_TEST_PENDING, (test) => this.addTestResult(test));
89
- runner.on(EVENT_TEST_FAIL, (test) => this.addTestResult(test));
93
+ runner.on(EVENT_TEST_PASS, (test) => {
94
+ this.markTestAsProcessed(test);
95
+ this.addTestResult(test);
96
+ });
97
+ runner.on(EVENT_TEST_PENDING, (test) => {
98
+ this.markTestAsProcessed(test);
99
+ this.addTestResult(test);
100
+ });
101
+ runner.on(EVENT_TEST_FAIL, (test) => {
102
+ this.markTestAsProcessed(test);
103
+ this.addTestResult(test);
104
+ });
90
105
  runner.on(EVENT_TEST_BEGIN, () => {
91
106
  this.testBeginTime = Date.now();
92
107
  manager_1.MetadataManager.clear();
93
108
  });
109
+ runner.on(EVENT_SUITE_END, (suite) => {
110
+ this.handleSkippedTestsInSuite(suite);
111
+ });
94
112
  // eslint-disable-next-line @typescript-eslint/no-misused-promises
95
113
  runner.once(EVENT_RUN_END, () => {
96
114
  const results = this.reporter.getResults();
97
115
  resultsManager_1.ResultsManager.setResults(results);
98
- // spawnSync('node', [`${__dirname}/child.js`], {
99
- // stdio: 'inherit',
100
- // env: Object.assign(process.env, {
101
- // reporterConfig: JSON.stringify(this.options),
102
- // results: JSON.stringify(results),
103
- // }),
104
- // });
116
+ this.processedTests.clear();
105
117
  });
106
118
  }
119
+ /**
120
+ * Generate a unique identifier for a test
121
+ * @param {Test} test
122
+ * @returns {string}
123
+ * @private
124
+ */
125
+ getTestIdentifier(test) {
126
+ const file = test.parent ? this.getFile(test.parent) ?? '' : '';
127
+ const suitePath = test.parent ? test.parent.titlePath().join(' > ') : '';
128
+ let testTitle = test.fullTitle();
129
+ // Remove "before each" hook prefix and quotes if present (can be anywhere in the string)
130
+ testTitle = testTitle.replace(/"before each" hook for "/g, '');
131
+ // Remove trailing quote if present
132
+ if (testTitle.endsWith('"')) {
133
+ testTitle = testTitle.slice(0, -1);
134
+ }
135
+ return `${file}::${suitePath}::${testTitle}`;
136
+ }
137
+ /**
138
+ * Mark a test as processed
139
+ * @param {Test} test
140
+ * @private
141
+ */
142
+ markTestAsProcessed(test) {
143
+ const identifier = this.getTestIdentifier(test);
144
+ this.processedTests.add(identifier);
145
+ }
146
+ /**
147
+ * Check if a test was processed
148
+ * @param {Test} test
149
+ * @returns {boolean}
150
+ * @private
151
+ */
152
+ isTestProcessed(test) {
153
+ const identifier = this.getTestIdentifier(test);
154
+ return this.processedTests.has(identifier);
155
+ }
156
+ /**
157
+ * Handle skipped tests in a suite when beforeEach hook fails
158
+ * @param {Suite} suite
159
+ * @private
160
+ */
161
+ /**
162
+ * Recursively collect all tests from a suite and its nested suites
163
+ * @param {Suite} suite
164
+ * @param {Test[]} tests
165
+ * @private
166
+ */
167
+ collectAllTestsFromSuite(suite, tests) {
168
+ // eslint-disable-next-line @typescript-eslint/no-explicit-any
169
+ const suiteTests = suite.tests ?? [];
170
+ tests.push(...suiteTests);
171
+ // Recursively process nested suites
172
+ const nestedSuites = suite.suites ?? [];
173
+ for (const nestedSuite of nestedSuites) {
174
+ this.collectAllTestsFromSuite(nestedSuite, tests);
175
+ }
176
+ }
177
+ handleSkippedTestsInSuite(suite) {
178
+ // Collect all tests from this suite and nested suites recursively
179
+ const allTests = [];
180
+ this.collectAllTestsFromSuite(suite, allTests);
181
+ // Find tests that were not processed (skipped due to beforeEach failure)
182
+ for (const test of allTests) {
183
+ // Skip if test was already processed (e.g., first test that got EVENT_TEST_FAIL)
184
+ if (!this.isTestProcessed(test)) {
185
+ // Test was skipped due to beforeEach failure, report it as skipped
186
+ this.addSkippedTestResult(test);
187
+ }
188
+ }
189
+ }
190
+ /**
191
+ * Add a test result for a skipped test (due to beforeEach failure)
192
+ * @param {Test} test
193
+ * @private
194
+ */
195
+ addSkippedTestResult(test) {
196
+ const end_time = Date.now();
197
+ const duration = 0; // Skipped tests have no duration
198
+ const start_time = this.testBeginTime || Date.now();
199
+ const ids = CypressQaseReporter.getCaseId(test.title);
200
+ const testFileName = this.getTestFileName(test);
201
+ const files = this.screenshotsFolder ?
202
+ fileSearcher_1.FileSearcher.findFilesBeforeTime(this.screenshotsFolder, testFileName, new Date(start_time))
203
+ : [];
204
+ const attachments = files.map((file) => ({
205
+ content: '',
206
+ id: (0, uuid_1.v4)(),
207
+ mime_type: 'image/png',
208
+ size: 0,
209
+ file_name: path_1.default.basename(file),
210
+ file_path: file,
211
+ }));
212
+ let relations = {};
213
+ if (test.parent !== undefined) {
214
+ const data = [];
215
+ for (const suite of test.parent.titlePath()) {
216
+ data.push({
217
+ title: suite,
218
+ public_id: null,
219
+ });
220
+ }
221
+ relations = {
222
+ suite: {
223
+ data: data,
224
+ },
225
+ };
226
+ }
227
+ // For skipped tests, we don't have metadata since the test never ran
228
+ // But we can still check for cucumber tags if the test has a parent with a file
229
+ if (test.parent) {
230
+ const file = this.getFile(test.parent);
231
+ if (file) {
232
+ const tags = (0, tagParser_1.extractTags)(file, test.title);
233
+ ids.push(...this.extractQaseIds(tags));
234
+ }
235
+ }
236
+ const result = {
237
+ attachments: attachments,
238
+ author: null,
239
+ fields: {},
240
+ message: null,
241
+ muted: false,
242
+ params: {},
243
+ group_params: {},
244
+ relations: relations,
245
+ run_id: null,
246
+ signature: this.getSignature(test, ids, {}),
247
+ steps: [],
248
+ id: (0, uuid_1.v4)(),
249
+ execution: {
250
+ status: qase_javascript_commons_1.TestStatusEnum.skipped,
251
+ start_time: this.testBeginTime / 1000,
252
+ end_time: end_time / 1000,
253
+ duration: duration,
254
+ stacktrace: null,
255
+ thread: null,
256
+ },
257
+ testops_id: ids.length > 0 ? ids : null,
258
+ title: this.removeQaseIdsFromTitle(test.title),
259
+ preparedAttachments: [],
260
+ };
261
+ void this.reporter.addTestResult(result);
262
+ // Mark as processed to avoid duplicate reporting
263
+ this.markTestAsProcessed(test);
264
+ }
107
265
  /**
108
266
  * @param {Test} test
109
267
  * @private
@@ -113,6 +271,8 @@ class CypressQaseReporter extends mocha_1.reporters.Base {
113
271
  const duration = end_time - this.testBeginTime;
114
272
  const metadata = manager_1.MetadataManager.getMetadata();
115
273
  if (metadata?.ignore) {
274
+ // Mark as processed even if ignored to avoid duplicate reporting
275
+ this.markTestAsProcessed(test);
116
276
  manager_1.MetadataManager.clear();
117
277
  return;
118
278
  }
@@ -198,7 +358,7 @@ class CypressQaseReporter extends mocha_1.reporters.Base {
198
358
  steps: steps,
199
359
  id: (0, uuid_1.v4)(),
200
360
  execution: {
201
- status: (0, qase_javascript_commons_1.determineTestStatus)(test.err || null, test.state || 'failed'),
361
+ status: (0, qase_javascript_commons_1.determineTestStatus)(test.err ?? null, test.state ?? 'failed'),
202
362
  start_time: this.testBeginTime / 1000,
203
363
  end_time: end_time / 1000,
204
364
  duration: duration,
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "cypress-qase-reporter",
3
- "version": "3.1.0",
3
+ "version": "3.1.2",
4
4
  "description": "Qase Cypress Reporter",
5
5
  "homepage": "https://github.com/qase-tms/qase-javascript",
6
6
  "sideEffects": false,
@@ -51,19 +51,19 @@
51
51
  "author": "Qase Team <support@qase.io>",
52
52
  "license": "Apache-2.0",
53
53
  "dependencies": {
54
- "qase-javascript-commons": "~2.4.5",
54
+ "qase-javascript-commons": "~2.4.14",
55
55
  "uuid": "^9.0.1"
56
56
  },
57
57
  "peerDependencies": {
58
58
  "cypress": ">=8.0.0"
59
59
  },
60
60
  "devDependencies": {
61
- "@jest/globals": "^29.5.0",
62
- "@types/jest": "^29.5.2",
63
- "@types/mocha": "^10.0.1",
64
- "ajv": "^8.12.0",
65
- "jest": "^29.5.0",
66
- "mocha": "^10.2.0",
67
- "ts-jest": "^29.1.0"
61
+ "@jest/globals": "^29.7.0",
62
+ "@types/jest": "^29.5.14",
63
+ "@types/mocha": "^10.0.10",
64
+ "ajv": "^8.17.1",
65
+ "jest": "^29.7.0",
66
+ "mocha": "^10.8.2",
67
+ "ts-jest": "^29.4.5"
68
68
  }
69
69
  }
@@ -2,7 +2,9 @@
2
2
  "extends": "./tsconfig.json",
3
3
 
4
4
  "compilerOptions": {
5
- "noEmit": false
5
+ "noEmit": false,
6
+ "skipLibCheck": true,
7
+ "types": []
6
8
  },
7
9
 
8
10
  "include": ["./src/**/*.ts", "./src/*.js"],