Skip to content

Commit 0c7386a

Browse files
author
DavertMik
committed
prepare 3.7 release
1 parent 676ed91 commit 0c7386a

File tree

3 files changed

+337
-9
lines changed

3 files changed

+337
-9
lines changed

CHANGELOG.md

Lines changed: 334 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,329 @@
1+
## 3.7.0
2+
3+
This release introduces major new features and internal refactoring. It is an important step toward the 4.0 release planned soon, which will remove all deprecations introduced in 3.7.
4+
5+
🛩️ _Features_
6+
7+
### 🔥 **[Element functions](./els)**
8+
9+
A new API for direct element interactions has been introduced. This API provides low-level element manipulation functions for more granular control over element interactions and assertions:
10+
11+
- `element()` - perform custom operations on first matching element
12+
- `eachElement()` - iterate and perform operations on each matching element
13+
- `expectElement()` - assert condition on first matching element
14+
- `expectAnyElement()` - assert condition matches at least one element
15+
- `expectAllElements()` - assert condition matches all elements
16+
17+
Example using all element functions:
18+
19+
```js
20+
const { element, eachElement, expectElement, expectAnyElement, expectAllElements } = require('codeceptjs/els')
21+
22+
// ...
23+
24+
Scenario('element functions demo', async ({ I }) => {
25+
// Get attribute of first button
26+
const attr = await element('.button', async el => await el.getAttribute('data-test'))
27+
28+
// Log text of each list item
29+
await eachElement('.list-item', async (el, idx) => {
30+
console.log(`Item ${idx}: ${await el.getText()}`)
31+
})
32+
33+
// Assert first submit button is enabled
34+
await expectElement('.submit', async el => await el.isEnabled())
35+
36+
// Assert at least one product is in stock
37+
await expectAnyElement('.product', async el => {
38+
return (await el.getAttribute('data-status')) === 'in-stock'
39+
})
40+
41+
// Assert all required fields have required attribute
42+
await expectAllElements('.required', async el => {
43+
return (await el.getAttribute('required')) !== null
44+
})
45+
})
46+
```
47+
48+
[Els](./els) functions expose the native API of Playwright, WebDriver, and Puppeteer helpers. The actual `el` API will differ depending on which helper is used, which affects test code interoperability.
49+
50+
### 🔮 **Effects introduced**
51+
52+
Effects is a new concept that encompasses all functions that can modify scenario flow. These functions are now part of a single module. Previously, they were used via plugins like `tryTo` and `retryTo`. Now, it is recommended to import them directly:
53+
54+
```js
55+
const { tryTo, retryTo } = require('codeceptjs/effects')
56+
57+
Scenario(..., ({ I }) => {
58+
I.amOnPage('/')
59+
// tryTo returns boolean if code in function fails
60+
// use it to execute actions that may fail but not affect the test flow
61+
// for instance, for accepting cookie banners
62+
const isItWorking = tryTo(() => I.see('It works'))
63+
64+
// run multiple steps and retry on failure
65+
retryTo(() => {
66+
I.click('Start Working!');
67+
I.see('It works')
68+
}, 5);
69+
})
70+
```
71+
72+
Previously `tryTo` and `retryTo` were available globally via plugins. This behavior is deprecated as of 3.7 and will be removed in 4.0. Import these functions via effects instead. Similarly, `within` will be moved to `effects` in 4.0.
73+
74+
#### **check command** added
75+
76+
```
77+
npx codeceptjs check
78+
```
79+
80+
This command can be executed locally or in CI environments to verify that tests can be executed correctly.
81+
82+
It checks:
83+
84+
- configuration
85+
- tests
86+
- helpers
87+
88+
And will attempt to open and close a browser if a corresponding helper is enabled. If something goes wrong, the command will fail with a message. Run `npx codeceptjs check` on CI before actual tests to ensure everything is set up correctly and all services and browsers are accessible.
89+
90+
For GitHub Actions, add this command:
91+
92+
```yaml
93+
steps:
94+
# ...
95+
- name: check configuration and browser
96+
run: npx codeceptjs check
97+
98+
- name: run codeceptjs tests
99+
run: npx codeceptjs run-workers 4
100+
```
101+
102+
### 👨‍🔬 **[analyze plugin](./plugins#analyze) introduced**
103+
104+
This AI plugin analyzes failures in test runs and provides brief summaries. For more than 5 failures, it performs cluster analysis and aggregates failures into groups, attempting to find common causes. It is recommended to use Deepseek R1 model or OpenAI o3 for better reasoning on clustering:
105+
106+
```js
107+
• SUMMARY The test failed because the expected text "Sign in" was not found on the page, indicating a possible issue with HTML elements or their visibility.
108+
• ERROR expected web application to include "Sign in"
109+
• CATEGORY HTML / page elements (not found, not visible, etc)
110+
• URL http://127.0.0.1:3000/users/sign_in
111+
```
112+
113+
For fewer than 5 failures, they are analyzed individually. If a visual recognition model is connected, AI will also scan screenshots to suggest potential failure causes (missing button, missing text, etc).
114+
115+
This plugin should be paired with the newly added [`pageInfo` plugin](./plugins/#pageInfo) which stores important information like URL, console logs, and error classes for further analysis.
116+
117+
### 👨‍💼 **autoLogin plugin** renamed to **auth plugin**
118+
119+
[`auth`](/plugins#auth) is the new name for the autoLogin plugin and aims to solve common authorization issues. In 3.7 it can use Playwright's storage state to load authorization cookies in a browser on start. So if a user is already authorized, a browser session starts with cookies already loaded for this user. If you use Playwright, you can enable this behavior using the `loginAs` method inside a `BeforeSuite` hook:
120+
121+
```js
122+
BeforeSuite(({ loginAs }) => loginAs('user'))
123+
```
124+
125+
The previous behavior where `loginAs` was called from a `Before` hook also works. However, cookie loading and authorization checking is performed after the browser starts.
126+
127+
#### Metadata introduced
128+
129+
Meta information in key-value format can be attached to Scenarios to provide more context when reporting tests:
130+
131+
```js
132+
// add Jira issue to scenario
133+
Scenario('...', () => {
134+
// ...
135+
}).meta('JIRA', 'TST-123')
136+
137+
// or pass meta info in the beginning of scenario:
138+
Scenario('my test linked to Jira', meta: { issue: 'TST-123' }, () => {
139+
// ...
140+
})
141+
```
142+
143+
By default, Playwright helpers add browser and window size as meta information to tests.
144+
145+
### 👢 Custom Steps API
146+
147+
Custom Steps or Sections API introduced to group steps into sections:
148+
149+
```js
150+
const { Section } = require('codeceptjs/steps');
151+
152+
Scenario({ I } => {
153+
I.amOnPage('/projects');
154+
155+
// start section "Create project"
156+
Section('Create a project');
157+
I.click('Create');
158+
I.fillField('title', 'Project 123')
159+
I.click('Save')
160+
I.see('Project created')
161+
// calling Section with empty param closes previous section
162+
Section()
163+
164+
// previous section automatically closes
165+
// when new section starts
166+
Section('open project')
167+
// ...
168+
});
169+
```
170+
171+
To hide steps inside a section from output use `Section().hidden()` call:
172+
173+
```js
174+
Section('Create a project').hidden()
175+
// next steps are not printed:
176+
I.click('Create')
177+
I.fillField('title', 'Project 123')
178+
Section()
179+
```
180+
181+
Alternative syntax for closing section: `EndSection`:
182+
183+
```js
184+
const { Section, EndSection } = require('codeceptjs/steps');
185+
186+
// ...
187+
Scenario(..., ({ I }) => // ...
188+
189+
Section('Create a project').hidden()
190+
// next steps are not printed:
191+
I.click('Create');
192+
I.fillField('title', 'Project 123')
193+
EndSection()
194+
```
195+
196+
Also available BDD-style pre-defined sections:
197+
198+
```js
199+
const { Given, When, Then } = require('codeceptjs/steps');
200+
201+
// ...
202+
Scenario(..., ({ I }) => // ...
203+
204+
Given('I have a project')
205+
// next steps are not printed:
206+
I.click('Create');
207+
I.fillField('title', 'Project 123')
208+
209+
When('I open project');
210+
// ...
211+
212+
Then('I should see analytics in a project')
213+
//....
214+
```
215+
216+
### 🥾 Step Options
217+
218+
Better syntax to set general step options for specific tests.
219+
220+
Use it to set timeout or retries for specific steps:
221+
222+
```js
223+
const step = require('codeceptjs/steps');
224+
225+
Scenario(..., ({ I }) => // ...
226+
I.click('Create', step.timeout(10).retry(2));
227+
//....
228+
```
229+
230+
Alternative syntax:
231+
232+
```js
233+
const { stepTimeout, stepRetry } = require('codeceptjs/steps');
234+
235+
Scenario(..., ({ I }) => // ...
236+
I.click('Create', stepTimeout(10));
237+
I.see('Created', stepRetry(2));
238+
//....
239+
```
240+
241+
This change deprecates previous syntax:
242+
243+
- `I.limitTime().act(...)` => replaced with `I.act(..., stepTimeout())`
244+
- `I.retry().act(...)` => replaced with `I.act(..., stepRetry())`
245+
246+
Step options should be passed as the very last argument to `I.action()` call.
247+
248+
Step options can be used to pass additional options to currently existing methods:
249+
250+
```js
251+
const { stepOpts } = require('codeceptjs/steps')
252+
253+
I.see('SIGN IN', stepOpts({ ignoreCase: true }))
254+
```
255+
256+
Currently this works only on `see` and only with `ignoreCase` param.
257+
However, this syntax will be extended in next versions.
258+
259+
#### Test object can be injected into Scenario
260+
261+
API for direct access to test object inside Scenario or hooks to add metadata or artifacts:
262+
263+
```js
264+
BeforeSuite(({ suite }) => {
265+
// no test object here, test is not created yet
266+
})
267+
268+
Before(({ test }) => {
269+
// add artifact to test
270+
test.artifacts.myScreenshot = 'screenshot'
271+
})
272+
273+
Scenario('test store-test-and-suite test', ({ test }) => {
274+
// add custom meta data
275+
test.meta.browser = 'chrome'
276+
})
277+
278+
After(({ test }) => {})
279+
```
280+
281+
Object for `suite` is also injected for all Scenario and hooks.
282+
283+
### Notable changes
284+
285+
- Load official Gherkin translations into CodeceptJS. See #4784 by @ebo-zig
286+
- 🇳🇱 `NL` translation introduced by @ebo-zig in #4784:
287+
- [Playwright] Improved experience to highlight and print elements in debug mode
288+
- `codeceptjs run` fails on CI if no tests were executed. This helps to avoid false positive checks. Use `DONT_FAIL_ON_EMPTY_RUN` env variable to disable this behavior
289+
- Various console output improvements
290+
- AI suggested fixes from `heal` plugin (which heals failing tests on the fly) shown in `run-workers` command
291+
- `plugin/standatdActingHelpers` replaced with `Container.STANDARD_ACTING_HELPERS`
292+
293+
### 🐛 _Bug Fixes_
294+
295+
- Fixed timeouts for `BeforeSuite` and `AfterSuite`
296+
- Fixed stucking process on session switch
297+
298+
### 🎇 Internal Refactoring
299+
300+
This section is listed briefly. A new dedicated page for internal API concepts will be added to documentation
301+
302+
- File structure changed:
303+
- mocha classes moved to `lib/mocha`
304+
- step is split to multiple classes and moved to `lib/step`
305+
- Extended and exposed to public API classes for Test, Suite, Hook
306+
- [Test](https://github.com/codeceptjs/CodeceptJS/blob/3.x/lib/mocha/test.js)
307+
- [Suite](https://github.com/codeceptjs/CodeceptJS/blob/3.x/lib/mocha/suite.js)
308+
- [Hook](https://github.com/codeceptjs/CodeceptJS/blob/3.x/lib/mocha/hooks.js) (Before, After, BeforeSuite, AfterSuite)
309+
- Container:
310+
- refactored to be prepared for async imports in ESM.
311+
- added proxy classes to resolve circular dependencies
312+
- Step
313+
- added different step types [`HelperStep`](https://github.com/codeceptjs/CodeceptJS/blob/3.x/lib/step/helper.js), [`MetaStep`](https://github.com/codeceptjs/CodeceptJS/blob/3.x/lib/step/meta.js), [`FuncStep`](https://github.com/codeceptjs/CodeceptJS/blob/3.x/lib/step/func.js), [`CommentStep`](https://github.com/codeceptjs/CodeceptJS/blob/3.x/lib/step/comment.js)
314+
- added `step.addToRecorder()` to schedule test execution as part of global promise chain
315+
- [Result object](https://github.com/codeceptjs/CodeceptJS/blob/3.x/lib/result.js) added
316+
- `event.all.result` now sends Result object with all failures and stats included
317+
- `run-workers` refactored to use `Result` to send results from workers to main process
318+
- Timeouts refactored `listener/timeout` => [`globalTimeout`](https://github.com/codeceptjs/CodeceptJS/blob/3.x/lib/listener/globalTimeout.js)
319+
- Reduced usages of global variables, more attributes added to [`store`](https://github.com/codeceptjs/CodeceptJS/blob/3.x/lib/store.js) to share data on current state between different parts of system
320+
- `events` API improved
321+
- Hook class is sent as param for `event.hook.passed`, `event.hook.finished`
322+
- `event.test.failed`, `event.test.finished` always sends Test. If test has failed in `Before` or `BeforeSuite` hook, event for all failed test in this suite will be sent
323+
- if a test has failed in a hook, a hook name is sent as 3rd arg to `event.test.failed`
324+
325+
---
326+
1327
## 3.6.10
2328
3329
❤️ Thanks all to those who contributed to make this release! ❤️
@@ -2442,7 +2768,7 @@ Read changelog to learn more about version 👇
24422768
24432769
```ts
24442770
const psp = wd.grabPageScrollPosition() // $ExpectType Promise<PageScrollPosition>
2445-
psp.then((result) => {
2771+
psp.then(result => {
24462772
result.x // $ExpectType number
24472773
result.y // $ExpectType number
24482774
})
@@ -3365,7 +3691,7 @@ This change allows using auto-completion when running a specific test.
33653691
- [WebDriverIO][Protractor][Multiple Sessions](https://codecept.io/acceptance/#multiple-sessions). Run several browser sessions in one test. Introduced `session` command, which opens additional browser window and closes it after a test.
33663692
33673693
```js
3368-
Scenario('run in different browsers', (I) => {
3694+
Scenario('run in different browsers', I => {
33693695
I.amOnPage('/hello')
33703696
I.see('Hello!')
33713697
session('john', () => {
@@ -3407,13 +3733,13 @@ locate('//table').find('tr').at(2).find('a').withText('Edit')
34073733
```js
34083734
Feature('checkout').timeout(3000).retry(2)
34093735
3410-
Scenario('user can order in firefox', (I) => {
3736+
Scenario('user can order in firefox', I => {
34113737
// see dynamic configuration
34123738
})
34133739
.config({ browser: 'firefox' })
34143740
.timeout(20000)
34153741
3416-
Scenario('this test should throw error', (I) => {
3742+
Scenario('this test should throw error', I => {
34173743
// I.amOnPage
34183744
}).throws(new Error())
34193745
```
@@ -3522,7 +3848,7 @@ I.retry({ retries: 3, maxTimeout: 3000 }).see('Hello')
35223848
// retry 2 times if error with message 'Node not visible' happens
35233849
I.retry({
35243850
retries: 2,
3525-
when: (err) => err.message === 'Node not visible',
3851+
when: err => err.message === 'Node not visible',
35263852
}).seeElement('#user')
35273853
```
35283854
@@ -3550,7 +3876,7 @@ I.retry({
35503876
35513877
```js
35523878
I.runOnAndroid(
3553-
(caps) => caps.platformVersion >= 7,
3879+
caps => caps.platformVersion >= 7,
35543880
() => {
35553881
// run code only on Android 7+
35563882
},
@@ -3959,7 +4285,7 @@ I.say('I expect post is visible on site')
39594285
```js
39604286
Feature('Complex JS Stuff', { retries: 3 })
39614287
3962-
Scenario('Not that complex', { retries: 1 }, (I) => {
4288+
Scenario('Not that complex', { retries: 1 }, I => {
39634289
// test goes here
39644290
})
39654291
```
@@ -3969,7 +4295,7 @@ Scenario('Not that complex', { retries: 1 }, (I) => {
39694295
```js
39704296
Feature('Complex JS Stuff', { timeout: 5000 })
39714297
3972-
Scenario('Not that complex', { timeout: 1000 }, (I) => {
4298+
Scenario('Not that complex', { timeout: 1000 }, I => {
39734299
// test goes here
39744300
})
39754301
```

0 commit comments

Comments
 (0)