@koenvanbelle/cypress-soft-assertions 1.0.6 → 1.0.8
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/dist/index.js +115 -104
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -9,49 +9,86 @@
|
|
|
9
9
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
10
10
|
let softAssertionErrors = [];
|
|
11
11
|
let isInSoftTest = false;
|
|
12
|
-
let
|
|
12
|
+
let activeFailHandler = null;
|
|
13
|
+
let activeSoftTestTitle = null;
|
|
14
|
+
let finalizerInstalled = false;
|
|
13
15
|
/**
|
|
14
|
-
*
|
|
16
|
+
* Track a soft assertion failure so it can be reported at test end.
|
|
15
17
|
*/
|
|
16
|
-
function
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
18
|
+
function captureSoftAssertion(error) {
|
|
19
|
+
const message = (error === null || error === void 0 ? void 0 : error.message) || String(error);
|
|
20
|
+
const stack = error === null || error === void 0 ? void 0 : error.stack;
|
|
21
|
+
const lastEntry = softAssertionErrors[softAssertionErrors.length - 1];
|
|
22
|
+
if (lastEntry && lastEntry.message === message && lastEntry.stack === stack) {
|
|
23
|
+
return;
|
|
20
24
|
}
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
// Don't throw - let the test continue
|
|
25
|
+
softAssertionErrors.push({
|
|
26
|
+
message,
|
|
27
|
+
stack
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Intercept Cypress failures and make assertion failures soft in soft_it() tests.
|
|
32
|
+
*/
|
|
33
|
+
function setupSoftAssertions() {
|
|
34
|
+
if (!activeFailHandler) {
|
|
35
|
+
activeFailHandler = (error) => {
|
|
36
|
+
if (!isInSoftTest) {
|
|
37
|
+
throw error;
|
|
35
38
|
}
|
|
39
|
+
captureSoftAssertion(error);
|
|
40
|
+
return false;
|
|
41
|
+
};
|
|
42
|
+
Cypress.on('fail', activeFailHandler);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
function getTestTitle(test) {
|
|
46
|
+
if (test && typeof test.fullTitle === 'function') {
|
|
47
|
+
return test.fullTitle();
|
|
48
|
+
}
|
|
49
|
+
return String((test === null || test === void 0 ? void 0 : test.title) || '');
|
|
50
|
+
}
|
|
51
|
+
function installFinalizer() {
|
|
52
|
+
if (finalizerInstalled) {
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
afterEach(function () {
|
|
56
|
+
var _a, _b;
|
|
57
|
+
if (!isInSoftTest) {
|
|
58
|
+
return;
|
|
36
59
|
}
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
60
|
+
const currentTest = (this.currentTest || this.test);
|
|
61
|
+
if (!currentTest || getTestTitle(currentTest) !== activeSoftTestTitle) {
|
|
62
|
+
return;
|
|
40
63
|
}
|
|
41
|
-
|
|
64
|
+
const finalError = finalizeSoftTest();
|
|
65
|
+
if (!finalError) {
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
currentTest.err = finalError;
|
|
69
|
+
currentTest.state = 'failed';
|
|
70
|
+
const runner = (_b = (_a = Cypress === null || Cypress === void 0 ? void 0 : Cypress.mocha) === null || _a === void 0 ? void 0 : _a.getRunner) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
71
|
+
if (runner && typeof runner.fail === 'function') {
|
|
72
|
+
runner.fail(currentTest, finalError);
|
|
73
|
+
return;
|
|
74
|
+
}
|
|
75
|
+
throw finalError;
|
|
76
|
+
});
|
|
77
|
+
finalizerInstalled = true;
|
|
42
78
|
}
|
|
43
79
|
/**
|
|
44
|
-
* Restore original Chai assertion behavior
|
|
80
|
+
* Restore original Chai assertion behavior.
|
|
45
81
|
*/
|
|
46
82
|
function restoreAssertions() {
|
|
47
|
-
if (
|
|
48
|
-
|
|
83
|
+
if (activeFailHandler) {
|
|
84
|
+
Cypress.off('fail', activeFailHandler);
|
|
85
|
+
activeFailHandler = null;
|
|
49
86
|
}
|
|
50
87
|
}
|
|
51
88
|
/**
|
|
52
89
|
* Report all collected soft assertion failures
|
|
53
90
|
*/
|
|
54
|
-
function
|
|
91
|
+
function buildSoftAssertionError() {
|
|
55
92
|
if (softAssertionErrors.length > 0) {
|
|
56
93
|
const errorMessages = softAssertionErrors
|
|
57
94
|
.map((entry, index) => ` ${index + 1}. ${entry.message}`)
|
|
@@ -66,13 +103,58 @@ function reportSoftAssertionFailures() {
|
|
|
66
103
|
''
|
|
67
104
|
].join('\n');
|
|
68
105
|
// Clear errors
|
|
69
|
-
const errorCount = softAssertionErrors.length;
|
|
70
106
|
softAssertionErrors = [];
|
|
71
|
-
// Throw the aggregated error
|
|
72
107
|
const error = new Error(finalMessage);
|
|
73
108
|
error.name = 'SoftAssertionError';
|
|
74
|
-
|
|
109
|
+
return error;
|
|
75
110
|
}
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
/**
|
|
114
|
+
* Cleanup soft assertion state and report accumulated failures.
|
|
115
|
+
*/
|
|
116
|
+
function finalizeSoftTest() {
|
|
117
|
+
isInSoftTest = false;
|
|
118
|
+
restoreAssertions();
|
|
119
|
+
activeSoftTestTitle = null;
|
|
120
|
+
return buildSoftAssertionError();
|
|
121
|
+
}
|
|
122
|
+
/**
|
|
123
|
+
* Cleanup soft assertion state without reporting (used on hard failures).
|
|
124
|
+
*/
|
|
125
|
+
function abortSoftTest() {
|
|
126
|
+
isInSoftTest = false;
|
|
127
|
+
restoreAssertions();
|
|
128
|
+
activeSoftTestTitle = null;
|
|
129
|
+
}
|
|
130
|
+
/**
|
|
131
|
+
* Create a soft_it variant from a Mocha it function.
|
|
132
|
+
*/
|
|
133
|
+
function createSoftIt(baseIt) {
|
|
134
|
+
installFinalizer();
|
|
135
|
+
return function (title, fn) {
|
|
136
|
+
return baseIt(title, function () {
|
|
137
|
+
isInSoftTest = true;
|
|
138
|
+
softAssertionErrors = [];
|
|
139
|
+
activeSoftTestTitle = getTestTitle(this.currentTest || this.test);
|
|
140
|
+
setupSoftAssertions();
|
|
141
|
+
try {
|
|
142
|
+
const result = fn.call(this);
|
|
143
|
+
if (result && typeof result.then === 'function') {
|
|
144
|
+
return result
|
|
145
|
+
.catch((error) => {
|
|
146
|
+
abortSoftTest();
|
|
147
|
+
throw error;
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
return result;
|
|
151
|
+
}
|
|
152
|
+
catch (error) {
|
|
153
|
+
abortSoftTest();
|
|
154
|
+
throw error;
|
|
155
|
+
}
|
|
156
|
+
});
|
|
157
|
+
};
|
|
76
158
|
}
|
|
77
159
|
/**
|
|
78
160
|
* soft_it - Define a test where all assertions are soft (non-blocking)
|
|
@@ -91,82 +173,11 @@ function reportSoftAssertionFailures() {
|
|
|
91
173
|
* cy.get('.city').should('have.text', 'NYC'); // Won't stop if fails
|
|
92
174
|
* });
|
|
93
175
|
*/
|
|
94
|
-
globalThis.soft_it =
|
|
95
|
-
return it(title, function () {
|
|
96
|
-
// Setup soft assertion mode
|
|
97
|
-
isInSoftTest = true;
|
|
98
|
-
softAssertionErrors = [];
|
|
99
|
-
setupSoftAssertions();
|
|
100
|
-
// Wrap the test function execution
|
|
101
|
-
const executeTest = () => {
|
|
102
|
-
try {
|
|
103
|
-
const result = fn.call(this);
|
|
104
|
-
// Handle async tests (Cypress tests return undefined, but we need to check after cy commands)
|
|
105
|
-
if (result && typeof result.then === 'function') {
|
|
106
|
-
return result.then(() => {
|
|
107
|
-
// Test completed - check for errors at the end
|
|
108
|
-
return cy.wrap(null).then(() => {
|
|
109
|
-
isInSoftTest = false;
|
|
110
|
-
reportSoftAssertionFailures();
|
|
111
|
-
});
|
|
112
|
-
}, (err) => {
|
|
113
|
-
isInSoftTest = false;
|
|
114
|
-
restoreAssertions();
|
|
115
|
-
throw err;
|
|
116
|
-
});
|
|
117
|
-
}
|
|
118
|
-
// For Cypress tests, we need to hook into the end of the command chain
|
|
119
|
-
return cy.wrap(null).then(() => {
|
|
120
|
-
isInSoftTest = false;
|
|
121
|
-
reportSoftAssertionFailures();
|
|
122
|
-
});
|
|
123
|
-
}
|
|
124
|
-
catch (err) {
|
|
125
|
-
isInSoftTest = false;
|
|
126
|
-
restoreAssertions();
|
|
127
|
-
throw err;
|
|
128
|
-
}
|
|
129
|
-
};
|
|
130
|
-
return executeTest();
|
|
131
|
-
});
|
|
132
|
-
};
|
|
176
|
+
globalThis.soft_it = createSoftIt(it);
|
|
133
177
|
/**
|
|
134
178
|
* soft_it.only - Run only this soft test
|
|
135
179
|
*/
|
|
136
|
-
globalThis.soft_it.only =
|
|
137
|
-
return it.only(title, function () {
|
|
138
|
-
isInSoftTest = true;
|
|
139
|
-
softAssertionErrors = [];
|
|
140
|
-
setupSoftAssertions();
|
|
141
|
-
const executeTest = () => {
|
|
142
|
-
try {
|
|
143
|
-
const result = fn.call(this);
|
|
144
|
-
if (result && typeof result.then === 'function') {
|
|
145
|
-
return result.then(() => {
|
|
146
|
-
return cy.wrap(null).then(() => {
|
|
147
|
-
isInSoftTest = false;
|
|
148
|
-
reportSoftAssertionFailures();
|
|
149
|
-
});
|
|
150
|
-
}, (err) => {
|
|
151
|
-
isInSoftTest = false;
|
|
152
|
-
restoreAssertions();
|
|
153
|
-
throw err;
|
|
154
|
-
});
|
|
155
|
-
}
|
|
156
|
-
return cy.wrap(null).then(() => {
|
|
157
|
-
isInSoftTest = false;
|
|
158
|
-
reportSoftAssertionFailures();
|
|
159
|
-
});
|
|
160
|
-
}
|
|
161
|
-
catch (err) {
|
|
162
|
-
isInSoftTest = false;
|
|
163
|
-
restoreAssertions();
|
|
164
|
-
throw err;
|
|
165
|
-
}
|
|
166
|
-
};
|
|
167
|
-
return executeTest();
|
|
168
|
-
});
|
|
169
|
-
};
|
|
180
|
+
globalThis.soft_it.only = createSoftIt(it.only);
|
|
170
181
|
/**
|
|
171
182
|
* soft_it.skip - Skip this soft test
|
|
172
183
|
*/
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@koenvanbelle/cypress-soft-assertions",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.8",
|
|
4
4
|
"description": "A Cypress plugin that provides soft_it() for soft assertions - all assertions continue on failure and are reported together",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"types": "dist/index.d.ts",
|