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 +12 -0
- package/dist/reporter.d.ts +45 -0
- package/dist/reporter.js +172 -12
- package/package.json +9 -9
- package/tsconfig.build.json +3 -1
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
|
package/dist/reporter.d.ts
CHANGED
|
@@ -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) =>
|
|
88
|
-
|
|
89
|
-
|
|
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
|
-
|
|
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
|
|
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.
|
|
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.
|
|
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.
|
|
62
|
-
"@types/jest": "^29.5.
|
|
63
|
-
"@types/mocha": "^10.0.
|
|
64
|
-
"ajv": "^8.
|
|
65
|
-
"jest": "^29.
|
|
66
|
-
"mocha": "^10.2
|
|
67
|
-
"ts-jest": "^29.
|
|
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
|
}
|