Skip to content

Commit 26bcd77

Browse files
author
Thanh Nguyen
committed
synchronized with docs
1 parent b0866a0 commit 26bcd77

11 files changed

Lines changed: 674 additions & 344 deletions

File tree

docs/build/Mochawesome.js

Lines changed: 7 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
let addMochawesomeContext
21
let currentTest
32
let currentSuite
43

@@ -16,7 +15,8 @@ class Mochawesome extends Helper {
1615
disableScreenshots: false,
1716
}
1817

19-
addMochawesomeContext = require('mochawesome/addContext')
18+
this._addContext = require('mochawesome/addContext')
19+
2020
this._createConfig(config)
2121
}
2222

@@ -44,28 +44,27 @@ class Mochawesome extends Helper {
4444
if (this.options.disableScreenshots) return
4545
let fileName
4646
// Get proper name if we are fail on hook
47-
if (test.ctx.test.type === 'hook') {
47+
if (test.ctx?.test?.type === 'hook') {
4848
currentTest = { test: test.ctx.test }
4949
// ignore retries if we are in hook
5050
test._retries = -1
5151
fileName = clearString(`${test.title}_${currentTest.test.title}`)
5252
} else {
5353
currentTest = { test }
54-
fileName = `${testToFileName(test)}`
54+
fileName = testToFileName(test)
5555
}
5656
if (this.options.uniqueScreenshotNames) {
57-
const uuid = test.uuid || test.ctx.test.uuid
58-
fileName = `${fileName.substring(0, 10)}_${uuid}`
57+
fileName = testToFileName(test, { unique: true })
5958
}
6059
if (test._retries < 1 || test._retries === test.retryNum) {
6160
fileName = `${fileName}.failed.png`
62-
return addMochawesomeContext(currentTest, fileName)
61+
return this._addContext(currentTest, fileName)
6362
}
6463
}
6564

6665
addMochawesomeContext(context) {
6766
if (currentTest === '') currentTest = { test: currentSuite.ctx.test }
68-
return addMochawesomeContext(currentTest, context)
67+
return this._addContext(currentTest, context)
6968
}
7069
}
7170

docs/build/Playwright.js

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3216,15 +3216,19 @@ class Playwright extends Helper {
32163216
if (this.options.recordVideo && this.page && this.page.video()) {
32173217
test.artifacts.video = saveVideoForPage(this.page, `${test.title}.failed`)
32183218
for (const sessionName in this.sessionPages) {
3219-
test.artifacts[`video_${sessionName}`] = saveVideoForPage(this.sessionPages[sessionName], `${test.title}_${sessionName}.failed`)
3219+
if (sessionName === '') continue
3220+
test.artifacts[`video_${sessionName}`] = saveVideoForPage(this.sessionPages[sessionName], `${sessionName}_${test.title}.failed`)
32203221
}
32213222
}
32223223

32233224
if (this.options.trace) {
32243225
test.artifacts.trace = await saveTraceForContext(this.browserContext, `${test.title}.failed`)
32253226
for (const sessionName in this.sessionPages) {
3226-
if (!this.sessionPages[sessionName].context) continue
3227-
test.artifacts[`trace_${sessionName}`] = await saveTraceForContext(this.sessionPages[sessionName].context, `${test.title}_${sessionName}.failed`)
3227+
if (sessionName === '') continue
3228+
const sessionPage = this.sessionPages[sessionName]
3229+
const sessionContext = sessionPage.context()
3230+
if (!sessionContext || !sessionContext.tracing) continue
3231+
test.artifacts[`trace_${sessionName}`] = await saveTraceForContext(sessionContext, `${sessionName}_${test.title}.failed`)
32283232
}
32293233
}
32303234

@@ -3238,7 +3242,8 @@ class Playwright extends Helper {
32383242
if (this.options.keepVideoForPassedTests) {
32393243
test.artifacts.video = saveVideoForPage(this.page, `${test.title}.passed`)
32403244
for (const sessionName of Object.keys(this.sessionPages)) {
3241-
test.artifacts[`video_${sessionName}`] = saveVideoForPage(this.sessionPages[sessionName], `${test.title}_${sessionName}.passed`)
3245+
if (sessionName === '') continue
3246+
test.artifacts[`video_${sessionName}`] = saveVideoForPage(this.sessionPages[sessionName], `${sessionName}_${test.title}.passed`)
32423247
}
32433248
} else {
32443249
this.page
@@ -3253,8 +3258,11 @@ class Playwright extends Helper {
32533258
if (this.options.trace) {
32543259
test.artifacts.trace = await saveTraceForContext(this.browserContext, `${test.title}.passed`)
32553260
for (const sessionName in this.sessionPages) {
3256-
if (!this.sessionPages[sessionName].context) continue
3257-
test.artifacts[`trace_${sessionName}`] = await saveTraceForContext(this.sessionPages[sessionName].context, `${test.title}_${sessionName}.passed`)
3261+
if (sessionName === '') continue
3262+
const sessionPage = this.sessionPages[sessionName]
3263+
const sessionContext = sessionPage.context()
3264+
if (!sessionContext || !sessionContext.tracing) continue
3265+
test.artifacts[`trace_${sessionName}`] = await saveTraceForContext(sessionContext, `${sessionName}_${test.title}.passed`)
32583266
}
32593267
}
32603268
} else {
@@ -5032,9 +5040,18 @@ function saveVideoForPage(page, name) {
50325040
async function saveTraceForContext(context, name) {
50335041
if (!context) return
50345042
if (!context.tracing) return
5035-
const fileName = `${`${global.output_dir}${pathSeparator}trace${pathSeparator}${uuidv4()}_${clearString(name)}`.slice(0, 245)}.zip`
5036-
await context.tracing.stop({ path: fileName })
5037-
return fileName
5043+
try {
5044+
const fileName = `${`${global.output_dir}${pathSeparator}trace${pathSeparator}${uuidv4()}_${clearString(name)}`.slice(0, 245)}.zip`
5045+
await context.tracing.stop({ path: fileName })
5046+
return fileName
5047+
} catch (err) {
5048+
// Handle the case where tracing was not started or context is invalid
5049+
if (err.message && err.message.includes('Must start tracing before stopping')) {
5050+
// Tracing was never started on this context, silently skip
5051+
return null
5052+
}
5053+
throw err
5054+
}
50385055
}
50395056

50405057
async function highlightActiveElement(element) {

docs/changelog.md

Lines changed: 122 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,128 @@ layout: Section
77

88
# Releases
99

10+
## 3.7.4
11+
12+
❤️ Thanks all to those who contributed to make this release! ❤️
13+
14+
🛩️ _Features_
15+
16+
- **Test Suite Shuffling**: Randomize test execution order to discover test dependencies and improve test isolation ([#5051](https://github.com/codeceptjs/CodeceptJS/issues/5051)) - by **[NivYarmus](https://github.com/NivYarmus)**
17+
18+
```bash
19+
# Shuffle tests to find order-dependent failures using lodash.shuffle algorithm
20+
npx codeceptjs run --shuffle
21+
22+
# Combined with grep and other options
23+
npx codeceptjs run --shuffle --grep "@smoke" --steps
24+
```
25+
26+
- **Enhanced Interactive Debugging**: Better logging for `I.grab*` methods in live interactive mode for clearer debugging output ([#4986](https://github.com/codeceptjs/CodeceptJS/issues/4986)) - by **[owenizedd](https://github.com/owenizedd)**
27+
28+
```js
29+
// Interactive pause() now shows detailed grab results with JSON formatting
30+
I.amOnPage('/checkout')
31+
pause() // Interactive shell started
32+
> I.grabTextFrom('.price')
33+
Result $res= "Grabbed text: $29.99" // Pretty-printed JSON output
34+
> I.grabValueFrom('input[name="email"]')
35+
{"value":"user@example.com"} // Structured JSON response
36+
```
37+
38+
🐛 _Bug Fixes_
39+
40+
- **Playwright Session Traces**: Fixed trace file naming convention and improved error handling for multi-session test scenarios ([#5073](https://github.com/codeceptjs/CodeceptJS/issues/5073)) - by **[julien-ft-64](https://github.com/julien-ft-64)** **[kobenguyent](https://github.com/kobenguyent)**
41+
42+
```js
43+
// Example outputs:
44+
// - a1b2c3d4-e5f6_checkout_login_test.failed.zip
45+
// - b2c3d4e5-f6g7_admin_dashboard_test.failed.zip
46+
```
47+
48+
_Trace files use UUID prefixes with `sessionName_testTitle.status.zip` format_
49+
50+
- **Worker Data Injection**: Resolved proxy object serialization preventing data sharing between parallel test workers ([#5072](https://github.com/codeceptjs/CodeceptJS/issues/5072)) - by **[kobenguyent](https://github.com/kobenguyent)**
51+
52+
```js
53+
// Fixed: Complex objects can now be properly shared and injected between workers
54+
// Bootstrap data sharing in codecept.conf.js:
55+
exports.config = {
56+
bootstrap() {
57+
share({
58+
userData: { id: 123, preferences: { theme: 'dark' } },
59+
apiConfig: { baseUrl: 'https://api.test.com', timeout: 5000 },
60+
})
61+
},
62+
}
63+
64+
// In tests across different workers:
65+
const testData = inject()
66+
console.log(testData.userData.preferences.theme) // 'dark' - deep nesting works
67+
console.log(Object.keys(testData)) // ['userData', 'apiConfig'] - key enumeration works
68+
69+
// Dynamic sharing during test execution:
70+
share({ newData: 'shared across workers' })
71+
```
72+
73+
- **Hook Exit Codes**: Fixed improper exit codes when test hooks fail, ensuring CI/CD pipelines properly detect failures ([#5058](https://github.com/codeceptjs/CodeceptJS/issues/5058)) - by **[kobenguyent](https://github.com/kobenguyent)**
74+
75+
```bash
76+
# Before: Exit code 0 even when beforeEach/afterEach failed
77+
# After: Exit code 1 when any hook fails, properly failing CI builds
78+
```
79+
80+
- **TypeScript Effects Support**: Added complete TypeScript definitions for effects functionality ([#5027](https://github.com/codeceptjs/CodeceptJS/issues/5027)) - by **[kobenguyent](https://github.com/kobenguyent)**
81+
82+
```typescript
83+
// Import effects with full TypeScript type definitions
84+
import { tryTo, retryTo, within } from 'codeceptjs/effects'
85+
86+
// tryTo returns Promise<boolean> for conditional actions
87+
const success: boolean = await tryTo(async () => {
88+
await I.see('Cookie banner')
89+
await I.click('Accept')
90+
})
91+
92+
// retryTo with typed parameters for reliability
93+
await retryTo(() => {
94+
I.click('Submit')
95+
I.see('Success')
96+
}, 3) // retry up to 3 times
97+
```
98+
99+
_Note: Replaces deprecated global plugins - import from 'codeceptjs/effects' module_
100+
101+
- **Mochawesome Screenshot Uniqueness**: Fixed screenshot naming to prevent test failures from being overwritten when multiple tests run at the same time ([#4959](https://github.com/codeceptjs/CodeceptJS/issues/4959)) - by **[Lando1n](https://github.com/Lando1n)**
102+
103+
```js
104+
// Problem: When tests run in parallel, screenshots had identical names
105+
// This caused later test screenshots to overwrite earlier ones
106+
107+
// Before: All failed tests saved as "screenshot.png"
108+
// Result: Only the last failure screenshot was kept
109+
110+
// After: Each screenshot gets a unique name with timestamp
111+
// Examples:
112+
// - "login_test_1645123456.failed.png"
113+
// - "checkout_test_1645123789.failed.png"
114+
// - "profile_test_1645124012.failed.png"
115+
116+
// Configuration in codecept.conf.js:
117+
helpers: {
118+
Mochawesome: {
119+
uniqueScreenshotNames: true // Enable unique naming
120+
}
121+
}
122+
```
123+
124+
_Ensures every failed test keeps its own screenshot for easier debugging_
125+
126+
📖 _Documentation_
127+
128+
- Fixed Docker build issues and improved container deployment process ([#4980](https://github.com/codeceptjs/CodeceptJS/issues/4980)) - by **[thomashohn](https://github.com/thomashohn)**
129+
- Updated dependency versions to maintain security and compatibility ([#4957](https://github.com/codeceptjs/CodeceptJS/issues/4957), [#4950](https://github.com/codeceptjs/CodeceptJS/issues/4950), [#4943](https://github.com/codeceptjs/CodeceptJS/issues/4943)) - by **[thomashohn](https://github.com/thomashohn)**
130+
- Fixed automatic documentation generation system for custom plugins ([#4973](https://github.com/codeceptjs/CodeceptJS/issues/4973)) - by **[Lando1n](https://github.com/Lando1n)**
131+
10132
## 3.7.3
11133

12134
❤️ Thanks all to those who contributed to make this release! ❤️
@@ -490,7 +612,6 @@ I.flushSoftAssertions() // Throws an error if any soft assertions have failed. T
490612
```
491613
492614
- feat(cli): print failed hooks ([#4476](https://github.com/codeceptjs/CodeceptJS/issues/4476)) - by **[kobenguyent](https://github.com/kobenguyent)**
493-
494615
- run command
495616
![Screenshot 2024-09-02 at 15 25 20](https://github.com/user-attachments/assets/625c6b54-03f6-41c6-9d0c-cd699582404a)
496617
@@ -750,7 +871,6 @@ heal.addRecipe('reloadPageIfModalIsNotVisisble', {
750871
```
751872
752873
- **Breaking Change** **AI** features refactored. Read updated [AI guide](./ai):
753-
754874
- **removed dependency on `openai`**
755875
- added support for **Azure OpenAI**, **Claude**, **Mistal**, or any AI via custom request function
756876
- `--ai` option added to explicitly enable AI features
@@ -761,7 +881,6 @@ heal.addRecipe('reloadPageIfModalIsNotVisisble', {
761881
- `OpenAI` helper renamed to `AI`
762882
763883
- feat(puppeteer): network traffic manipulation. See [#4263](https://github.com/codeceptjs/CodeceptJS/issues/4263) by **[KobeNguyenT](https://github.com/KobeNguyenT)**
764-
765884
- `startRecordingTraffic`
766885
- `grabRecordedNetworkTraffics`
767886
- `flushNetworkTraffics`
@@ -2099,7 +2218,6 @@ await I.seeTraffic({
20992218

21002219
- **🪄 [AI Powered Test Automation](/ai)** - use OpenAI as a copilot for test automation. [#3713](https://github.com/codeceptjs/CodeceptJS/issues/3713) By **[davertmik](https://github.com/davertmik)**
21012220
![](https://user-images.githubusercontent.com/220264/250418764-c382709a-3ccb-4eb5-b6bc-538f3b3b3d35.png)
2102-
21032221
- [AI guide](/ai) added
21042222
- added support for OpenAI in `pause()`
21052223
- added [`heal` plugin](/plugins#heal) for self-healing tests
@@ -2110,7 +2228,6 @@ await I.seeTraffic({
21102228
![](https://user-images.githubusercontent.com/220264/250415226-a7620418-56a4-4837-b790-b15e91e5d1f0.png)
21112229
21122230
- **[Playwright]** Support for APIs in Playwright ([#3665](https://github.com/codeceptjs/CodeceptJS/issues/3665)) - by Egor Bodnar
2113-
21142231
- `clearField` replaced to use new Playwright API
21152232
- `blur` added
21162233
- `focus` added
@@ -3521,9 +3638,7 @@ I.seeFile(fileName)
35213638
## 2.0.0
35223639
35233640
- **[WebDriver]** **Breaking Change.** Updated to webdriverio v5. New helper **WebDriver** helper introduced.
3524-
35253641
- **Upgrade plan**:
3526-
35273642
1. Install latest webdriverio
35283643
35293644
```
@@ -3540,9 +3655,7 @@ I.seeFile(fileName)
35403655

35413656
- **[Appium]** **Breaking Change.** Updated to use webdriverio v5 as well. See upgrade plan
35423657
- **[REST]** **Breaking Change.** Replaced `unirest` library with `axios`.
3543-
35443658
- **Upgrade plan**:
3545-
35463659
1. Refer to [axios API](https://github.com/axios/axios).
35473660
2. If you were using `unirest` requests/responses in your tests change them to axios format.
35483661

docs/commands.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,12 @@ Run single test with steps printed
4747
npx codeceptjs run github_test.js --steps
4848
```
4949

50+
Run test files in shuffled order
51+
52+
```sh
53+
npx codeceptjs run --shuffle
54+
```
55+
5056
Run single test in debug mode (see more in [debugging](#Debugging) section)
5157

5258
```sh

docs/examples.md

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -152,4 +152,7 @@ This is necessary if all integrations with TMS and CI/CD are already configured,
152152
* Tests are written in TS
153153
* CI/CD with Github Actions
154154
* Page Object Model is applied
155-
* ReportPortal Integration
155+
* ReportPortal Integration
156+
157+
## How to
158+
* Create a plugin with TS [link](https://github.com/reutenkoivan/codeceptjs-plugins/tree/main/packages/html-snapshot-on-fail)

0 commit comments

Comments
 (0)