Skip to content

Commit c503ea2

Browse files
authoredJan 10, 2025··
feat: soft assertion (#4728)
* feat: soft assertion * update as hopeThat module in effects * fix: docs
1 parent b960479 commit c503ea2

File tree

2 files changed

+150
-0
lines changed

2 files changed

+150
-0
lines changed
 

‎lib/effects.js

+123
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
const recorder = require('./recorder')
2+
const { debug } = require('./output')
3+
const store = require('./store')
4+
5+
/**
6+
* @module hopeThat
7+
*
8+
* `hopeThat` is a utility function for CodeceptJS tests that allows for soft assertions.
9+
* It enables conditional assertions without terminating the test upon failure.
10+
* This is particularly useful in scenarios like A/B testing, handling unexpected elements,
11+
* or performing multiple assertions where you want to collect all results before deciding
12+
* on the test outcome.
13+
*
14+
* ## Use Cases
15+
*
16+
* - **Multiple Conditional Assertions**: Perform several assertions and evaluate all their outcomes together.
17+
* - **A/B Testing**: Handle different variants in A/B tests without failing the entire test upon one variant's failure.
18+
* - **Unexpected Elements**: Manage elements that may or may not appear, such as "Accept Cookie" banners.
19+
*
20+
* ## Examples
21+
*
22+
* ### Multiple Conditional Assertions
23+
*
24+
* Add the assertion library:
25+
* ```js
26+
* const assert = require('assert');
27+
* const { hopeThat } = require('codeceptjs/effects');
28+
* ```
29+
*
30+
* Use `hopeThat` with assertions:
31+
* ```js
32+
* const result1 = await hopeThat(() => I.see('Hello, user'));
33+
* const result2 = await hopeThat(() => I.seeElement('.welcome'));
34+
* assert.ok(result1 && result2, 'Assertions were not successful');
35+
* ```
36+
*
37+
* ### Optional Click
38+
*
39+
* ```js
40+
* const { hopeThat } = require('codeceptjs/effects');
41+
*
42+
* I.amOnPage('/');
43+
* await hopeThat(() => I.click('Agree', '.cookies'));
44+
* ```
45+
*
46+
* Performs a soft assertion within CodeceptJS tests.
47+
*
48+
* This function records the execution of a callback containing assertion logic.
49+
* If the assertion fails, it logs the failure without stopping the test execution.
50+
* It is useful for scenarios where multiple assertions are performed, and you want
51+
* to evaluate all outcomes before deciding on the test result.
52+
*
53+
* ## Usage
54+
*
55+
* ```js
56+
* const result = await hopeThat(() => I.see('Welcome'));
57+
*
58+
* // If the text "Welcome" is on the page, result => true
59+
* // If the text "Welcome" is not on the page, result => false
60+
* ```
61+
*
62+
* @async
63+
* @function hopeThat
64+
* @param {Function} callback - The callback function containing the soft assertion logic.
65+
* @returns {Promise<boolean | any>} - Resolves to `true` if the assertion is successful, or `false` if it fails.
66+
*
67+
* @example
68+
* // Multiple Conditional Assertions
69+
* const assert = require('assert');
70+
* const { hopeThat } = require('codeceptjs/effects');
71+
*
72+
* const result1 = await hopeThat(() => I.see('Hello, user'));
73+
* const result2 = await hopeThat(() => I.seeElement('.welcome'));
74+
* assert.ok(result1 && result2, 'Assertions were not successful');
75+
*
76+
* @example
77+
* // Optional Click
78+
* const { hopeThat } = require('codeceptjs/effects');
79+
*
80+
* I.amOnPage('/');
81+
* await hopeThat(() => I.click('Agree', '.cookies'));
82+
*/
83+
async function hopeThat(callback) {
84+
if (store.dryRun) return
85+
const sessionName = 'hopeThat'
86+
87+
let result = false
88+
return recorder.add(
89+
'hopeThat',
90+
() => {
91+
recorder.session.start(sessionName)
92+
store.hopeThat = true
93+
callback()
94+
recorder.add(() => {
95+
result = true
96+
recorder.session.restore(sessionName)
97+
return result
98+
})
99+
recorder.session.catch(err => {
100+
result = false
101+
const msg = err.inspect ? err.inspect() : err.toString()
102+
debug(`Unsuccessful assertion > ${msg}`)
103+
recorder.session.restore(sessionName)
104+
return result
105+
})
106+
return recorder.add(
107+
'result',
108+
() => {
109+
store.hopeThat = undefined
110+
return result
111+
},
112+
true,
113+
false,
114+
)
115+
},
116+
false,
117+
false,
118+
)
119+
}
120+
121+
module.exports = {
122+
hopeThat,
123+
}

‎test/unit/hopeThat_test.js

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
const { expect } = require('chai')
2+
const { hopeThat } = require('../../lib/effects')
3+
const recorder = require('../../lib/recorder')
4+
5+
describe('effects', () => {
6+
describe('hopeThat', () => {
7+
beforeEach(() => {
8+
recorder.start()
9+
})
10+
11+
it('should execute command on success', async () => {
12+
const ok = await hopeThat(() => recorder.add(() => 5))
13+
expect(true).is.equal(ok)
14+
return recorder.promise()
15+
})
16+
17+
it('should execute command on fail', async () => {
18+
const notOk = await hopeThat(() =>
19+
recorder.add(() => {
20+
throw new Error('Ups')
21+
}),
22+
)
23+
expect(false).is.equal(notOk)
24+
return recorder.promise()
25+
})
26+
})
27+
})

0 commit comments

Comments
 (0)
Please sign in to comment.