@koenvanbelle/cypress-soft-assertions 2.3.1 → 2.3.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/README.md +30 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.js +46 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -249,6 +249,36 @@ soft_it('works with automatic translation checks', () => {
|
|
|
249
249
|
- Both plugins register hooks/events, but they can run together safely with the setup above.
|
|
250
250
|
- Keep translation-checker in non-invasive mode (`failOnError: false` in auto mode) so functional assertions remain the source of test pass/fail behavior.
|
|
251
251
|
|
|
252
|
+
## Force-Fail Hook (strict mode)
|
|
253
|
+
|
|
254
|
+
If your project (or another plugin) mutates test state in hooks (for example in `test:after:run`) and soft-failed tests appear as passed, enable strict mode per test:
|
|
255
|
+
|
|
256
|
+
```typescript
|
|
257
|
+
soft_it.strict('fails hard when soft assertions are captured', () => {
|
|
258
|
+
cy.visit('/');
|
|
259
|
+
cy.get('#title').should('have.text', 'Wrong Title');
|
|
260
|
+
cy.get('#status').should('have.text', 'Ready');
|
|
261
|
+
});
|
|
262
|
+
```
|
|
263
|
+
|
|
264
|
+
You can also use `soft_it.strict.only(...)` and `soft_it.strict.skip(...)`.
|
|
265
|
+
|
|
266
|
+
To force strict mode for all soft tests in a run, use env flags:
|
|
267
|
+
|
|
268
|
+
```bash
|
|
269
|
+
cypress run --env softAssertForceFail=true
|
|
270
|
+
```
|
|
271
|
+
|
|
272
|
+
You can also use:
|
|
273
|
+
|
|
274
|
+
```bash
|
|
275
|
+
cypress run --env SOFT_ASSERT_FORCE_FAIL=true
|
|
276
|
+
```
|
|
277
|
+
|
|
278
|
+
When strict mode is enabled (per test or via env), the plugin throws the final `SoftAssertionError` from `afterEach` on the last attempt, preventing downstream hook-based recovery from turning the test green.
|
|
279
|
+
|
|
280
|
+
Note: strict mode may abort remaining tests in the same suite after the first forced soft failure (standard Cypress hook-failure behavior).
|
|
281
|
+
|
|
252
282
|
## License
|
|
253
283
|
|
|
254
284
|
MIT
|
package/dist/index.d.ts
CHANGED
|
@@ -39,6 +39,16 @@ declare global {
|
|
|
39
39
|
* Run only this test (like it.only)
|
|
40
40
|
*/
|
|
41
41
|
function only(title: string, fn: Mocha.Func | Mocha.AsyncFunc): Mocha.Test;
|
|
42
|
+
/**
|
|
43
|
+
* Run this soft test in strict mode (force unrecoverable failure)
|
|
44
|
+
*/
|
|
45
|
+
function strict(title: string, fn: Mocha.Func | Mocha.AsyncFunc): Mocha.Test;
|
|
46
|
+
namespace strict {
|
|
47
|
+
/** Run only this strict soft test */
|
|
48
|
+
function only(title: string, fn: Mocha.Func | Mocha.AsyncFunc): Mocha.Test;
|
|
49
|
+
/** Skip this strict soft test */
|
|
50
|
+
function skip(title: string, fn: Mocha.Func | Mocha.AsyncFunc): void;
|
|
51
|
+
}
|
|
42
52
|
/**
|
|
43
53
|
* Skip this test (like it.skip)
|
|
44
54
|
*/
|
package/dist/index.js
CHANGED
|
@@ -20,6 +20,7 @@ let softAssertionErrors = [];
|
|
|
20
20
|
let retryAssertionFailures = new Map();
|
|
21
21
|
let retryFirstSeen = new Map();
|
|
22
22
|
let isInSoftTest = false;
|
|
23
|
+
let forceFailCurrentSoftTest = false;
|
|
23
24
|
let activeFailHandler = null;
|
|
24
25
|
let originalChaiAssert = null;
|
|
25
26
|
// ---------------------------------------------------------------------------
|
|
@@ -41,6 +42,26 @@ function getEffectiveTimeout() {
|
|
|
41
42
|
return 4000;
|
|
42
43
|
}
|
|
43
44
|
}
|
|
45
|
+
function isTruthy(value) {
|
|
46
|
+
if (typeof value === 'boolean')
|
|
47
|
+
return value;
|
|
48
|
+
if (typeof value === 'number')
|
|
49
|
+
return value !== 0;
|
|
50
|
+
const normalized = String(value !== null && value !== void 0 ? value : '').trim().toLowerCase();
|
|
51
|
+
return normalized === '1' || normalized === 'true' || normalized === 'yes' || normalized === 'on';
|
|
52
|
+
}
|
|
53
|
+
function shouldForceFailSoftAssertions() {
|
|
54
|
+
var _a;
|
|
55
|
+
try {
|
|
56
|
+
const env = (_a = Cypress.env) === null || _a === void 0 ? void 0 : _a.bind(Cypress);
|
|
57
|
+
if (!env)
|
|
58
|
+
return false;
|
|
59
|
+
return isTruthy(env('softAssertForceFail')) || isTruthy(env('SOFT_ASSERT_FORCE_FAIL'));
|
|
60
|
+
}
|
|
61
|
+
catch (_b) {
|
|
62
|
+
return false;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
44
65
|
// ---------------------------------------------------------------------------
|
|
45
66
|
// Internal helpers (Cypress-dependent — not unit-testable in isolation)
|
|
46
67
|
// ---------------------------------------------------------------------------
|
|
@@ -208,19 +229,22 @@ function buildSoftAssertionError() {
|
|
|
208
229
|
}
|
|
209
230
|
function finalizeSoftTest() {
|
|
210
231
|
isInSoftTest = false;
|
|
232
|
+
forceFailCurrentSoftTest = false;
|
|
211
233
|
restoreAssertions();
|
|
212
234
|
return buildSoftAssertionError();
|
|
213
235
|
}
|
|
214
236
|
function abortSoftTest() {
|
|
215
237
|
isInSoftTest = false;
|
|
238
|
+
forceFailCurrentSoftTest = false;
|
|
216
239
|
restoreAssertions();
|
|
217
240
|
retryAssertionFailures.clear();
|
|
218
241
|
retryFirstSeen.clear();
|
|
219
242
|
}
|
|
220
|
-
function createSoftIt(baseIt) {
|
|
243
|
+
function createSoftIt(baseIt, options) {
|
|
221
244
|
return function (title, fn) {
|
|
222
245
|
return baseIt(title, function () {
|
|
223
246
|
isInSoftTest = true;
|
|
247
|
+
forceFailCurrentSoftTest = Boolean(options === null || options === void 0 ? void 0 : options.strict) || shouldForceFailSoftAssertions();
|
|
224
248
|
softAssertionErrors = [];
|
|
225
249
|
retryAssertionFailures.clear();
|
|
226
250
|
retryFirstSeen.clear();
|
|
@@ -257,10 +281,25 @@ globalThis.soft_it = createSoftIt(it);
|
|
|
257
281
|
* soft_it.only - Run only this soft test
|
|
258
282
|
*/
|
|
259
283
|
globalThis.soft_it.only = createSoftIt(it.only);
|
|
284
|
+
/**
|
|
285
|
+
* soft_it.strict - Run this soft test in strict mode.
|
|
286
|
+
*
|
|
287
|
+
* Strict mode throws the final SoftAssertionError from afterEach on the
|
|
288
|
+
* last attempt, making the failure unrecoverable by downstream hooks.
|
|
289
|
+
*/
|
|
290
|
+
globalThis.soft_it.strict = createSoftIt(it, { strict: true });
|
|
291
|
+
/**
|
|
292
|
+
* soft_it.strict.only - Run only this strict soft test
|
|
293
|
+
*/
|
|
294
|
+
globalThis.soft_it.strict.only = createSoftIt(it.only, { strict: true });
|
|
260
295
|
/**
|
|
261
296
|
* soft_it.skip - Skip this soft test
|
|
262
297
|
*/
|
|
263
298
|
globalThis.soft_it.skip = it.skip;
|
|
299
|
+
/**
|
|
300
|
+
* soft_it.strict.skip - Skip this strict soft test
|
|
301
|
+
*/
|
|
302
|
+
globalThis.soft_it.strict.skip = it.skip;
|
|
264
303
|
// Global afterEach hook: finalize soft assertions after each test.
|
|
265
304
|
// Registered at the root level so it applies to all suites.
|
|
266
305
|
// For non-soft tests (isInSoftTest === false), this is a no-op.
|
|
@@ -282,6 +321,12 @@ afterEach(function () {
|
|
|
282
321
|
// Last (or only) attempt — use runner.fail() to mark the TEST as failed
|
|
283
322
|
// rather than the hook. Throwing from afterEach on the final attempt
|
|
284
323
|
// would skip remaining tests in the suite.
|
|
324
|
+
if (forceFailCurrentSoftTest) {
|
|
325
|
+
// Strict mode: force an unrecoverable hook failure.
|
|
326
|
+
// This guarantees a failed result even when other plugins mutate
|
|
327
|
+
// test state in test:after:run.
|
|
328
|
+
throw finalError;
|
|
329
|
+
}
|
|
285
330
|
const runner = (_c = Cypress.mocha) === null || _c === void 0 ? void 0 : _c.getRunner();
|
|
286
331
|
if (runner && test) {
|
|
287
332
|
runner.fail(test, finalError);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@koenvanbelle/cypress-soft-assertions",
|
|
3
|
-
"version": "2.3.
|
|
3
|
+
"version": "2.3.2",
|
|
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",
|