codeceptjs 4.0.1-beta.9 → 4.0.1
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 +39 -28
- package/bin/codecept.js +17 -4
- package/bin/codeceptq.js +49 -0
- package/bin/mcp-server.js +1189 -0
- package/docs/advanced.md +201 -0
- package/docs/agents.md +181 -0
- package/docs/ai.md +489 -0
- package/docs/aitrace.md +266 -0
- package/docs/api.md +332 -0
- package/docs/architecture.md +235 -0
- package/docs/assertions.md +415 -0
- package/docs/auth.md +318 -0
- package/docs/basics.md +424 -0
- package/docs/bdd.md +539 -0
- package/docs/best.md +240 -0
- package/docs/bootstrap.md +132 -0
- package/docs/commands.md +352 -0
- package/docs/community-helpers.md +63 -0
- package/docs/configuration.md +185 -0
- package/docs/continuous-integration.md +431 -0
- package/docs/custom-helpers.md +297 -0
- package/docs/data.md +448 -0
- package/docs/debugging.md +332 -0
- package/docs/detox.md +235 -0
- package/docs/docker.md +107 -0
- package/docs/effects.md +179 -0
- package/docs/element-based-testing.md +295 -0
- package/docs/element-selection.md +125 -0
- package/docs/els.md +328 -0
- package/docs/environment-variables.md +131 -0
- package/docs/examples.md +160 -0
- package/docs/heal.md +213 -0
- package/docs/helpers/ApiDataFactory.md +267 -0
- package/docs/helpers/Appium.md +1419 -0
- package/docs/helpers/Detox.md +665 -0
- package/docs/helpers/ExpectHelper.md +275 -0
- package/docs/helpers/FileSystem.md +152 -0
- package/docs/helpers/GraphQL.md +152 -0
- package/docs/helpers/GraphQLDataFactory.md +226 -0
- package/docs/helpers/JSONResponse.md +255 -0
- package/docs/helpers/MockRequest.md +377 -0
- package/docs/helpers/Playwright.md +2970 -0
- package/docs/helpers/Puppeteer-firefox.md +86 -0
- package/docs/helpers/Puppeteer.md +2583 -0
- package/docs/helpers/REST.md +289 -0
- package/docs/helpers/WebDriver.md +2639 -0
- package/docs/hooks.md +148 -0
- package/docs/index.md +111 -0
- package/docs/installation.md +121 -0
- package/docs/internal-test-server.md +89 -0
- package/docs/locators.md +355 -0
- package/docs/mcp.md +485 -0
- package/docs/migrate-from-cypress.md +98 -0
- package/docs/migrate-from-java.md +108 -0
- package/docs/migrate-from-protractor.md +101 -0
- package/docs/migrate-from-testcafe.md +99 -0
- package/docs/migration-4.md +745 -0
- package/docs/mobile.md +338 -0
- package/docs/pageobjects.md +399 -0
- package/docs/parallel.md +187 -0
- package/docs/playwright.md +714 -0
- package/docs/plugins/aiTrace.md +49 -0
- package/docs/plugins/analyze.md +66 -0
- package/docs/plugins/auth.md +241 -0
- package/docs/plugins/autoDelay.md +48 -0
- package/docs/plugins/browser.md +41 -0
- package/docs/plugins/coverage.md +39 -0
- package/docs/plugins/customLocator.md +119 -0
- package/docs/plugins/customReporter.md +16 -0
- package/docs/plugins/expose.md +75 -0
- package/docs/plugins/heal.md +44 -0
- package/docs/plugins/junitReporter.md +51 -0
- package/docs/plugins/pageInfo.md +34 -0
- package/docs/plugins/pause.md +43 -0
- package/docs/plugins/pauseOnFail.md +18 -0
- package/docs/plugins/retryFailedStep.md +75 -0
- package/docs/plugins/screencast.md +55 -0
- package/docs/plugins/screenshot.md +58 -0
- package/docs/plugins/screenshotOnFail.md +18 -0
- package/docs/plugins/stepTimeout.md +65 -0
- package/docs/plugins.md +87 -0
- package/docs/puppeteer.md +314 -0
- package/docs/quickstart.md +120 -0
- package/docs/reports.md +195 -0
- package/docs/retry.md +311 -0
- package/docs/secrets.md +150 -0
- package/docs/sessions.md +80 -0
- package/docs/shadow.md +68 -0
- package/docs/store.md +94 -0
- package/docs/test-structure.md +275 -0
- package/docs/timeouts.md +183 -0
- package/docs/translation.md +247 -0
- package/docs/tutorial.md +323 -0
- package/docs/typescript.md +159 -0
- package/docs/web-element.md +251 -0
- package/docs/webdriver.md +641 -0
- package/docs/within.md +55 -0
- package/lib/actor.js +1 -36
- package/lib/ai.js +3 -2
- package/lib/aria.js +260 -0
- package/lib/assertions.js +18 -0
- package/lib/codecept.js +34 -25
- package/lib/command/check.js +2 -1
- package/lib/command/definitions.js +14 -10
- package/lib/command/dryRun.js +24 -5
- package/lib/command/generate.js +3 -1
- package/lib/command/gherkin/snippets.js +5 -4
- package/lib/command/init.js +249 -270
- package/lib/command/list.js +150 -10
- package/lib/command/query.js +218 -0
- package/lib/command/run-multiple.js +3 -2
- package/lib/command/run-workers.js +14 -16
- package/lib/command/run.js +3 -17
- package/lib/command/utils.js +14 -0
- package/lib/command/workers/runTests.js +117 -9
- package/lib/config.js +98 -19
- package/lib/container.js +188 -19
- package/lib/effects.js +17 -0
- package/lib/element/WebElement.js +246 -2
- package/lib/els.js +12 -6
- package/lib/globals.js +32 -19
- package/lib/heal.js +7 -4
- package/lib/helper/ApiDataFactory.js +2 -1
- package/lib/helper/Appium.js +8 -8
- package/lib/helper/FileSystem.js +3 -2
- package/lib/helper/GraphQLDataFactory.js +2 -1
- package/lib/helper/Playwright.js +367 -516
- package/lib/helper/Puppeteer.js +343 -197
- package/lib/helper/WebDriver.js +324 -111
- package/lib/helper/errors/ElementNotFound.js +5 -2
- package/lib/helper/errors/MultipleElementsFound.js +52 -0
- package/lib/helper/errors/NonFocusedType.js +8 -0
- package/lib/helper/extras/Download.js +45 -0
- package/lib/helper/extras/PlaywrightLocator.js +7 -107
- package/lib/helper/extras/elementSelection.js +58 -0
- package/lib/helper/extras/focusCheck.js +43 -0
- package/lib/helper/extras/richTextEditor.js +178 -0
- package/lib/helper/scripts/dropFile.js +11 -0
- package/lib/history.js +3 -2
- package/lib/html.js +103 -16
- package/lib/index.js +9 -1
- package/lib/listener/config.js +6 -4
- package/lib/listener/emptyRun.js +2 -1
- package/lib/listener/globalRetry.js +32 -6
- package/lib/listener/helpers.js +6 -15
- package/lib/listener/mocha.js +2 -1
- package/lib/listener/pageobjects.js +43 -0
- package/lib/listener/result.js +3 -2
- package/lib/locator.js +158 -16
- package/lib/mocha/cli.js +19 -1
- package/lib/mocha/factory.js +13 -28
- package/lib/mocha/inject.js +1 -1
- package/lib/mocha/scenarioConfig.js +2 -1
- package/lib/mocha/test.js +4 -2
- package/lib/mocha/ui.js +5 -6
- package/lib/output.js +2 -2
- package/lib/parser.js +2 -2
- package/lib/pause.js +38 -4
- package/lib/plugin/aiTrace.js +457 -0
- package/lib/plugin/analyze.js +9 -9
- package/lib/plugin/auth.js +5 -4
- package/lib/plugin/browser.js +77 -0
- package/lib/plugin/expose.js +159 -0
- package/lib/plugin/heal.js +47 -3
- package/lib/plugin/junitReporter.js +303 -0
- package/lib/plugin/pageInfo.js +54 -52
- package/lib/plugin/pause.js +131 -0
- package/lib/plugin/pauseOnFail.js +11 -33
- package/lib/plugin/retryFailedStep.js +43 -32
- package/lib/plugin/screencast.js +289 -0
- package/lib/plugin/screenshot.js +558 -0
- package/lib/plugin/screenshotOnFail.js +9 -170
- package/lib/plugin/stepTimeout.js +3 -2
- package/lib/recorder.js +1 -1
- package/lib/rerun.js +2 -1
- package/lib/result.js +2 -1
- package/lib/step/base.js +23 -9
- package/lib/step/comment.js +2 -2
- package/lib/step/config.js +15 -2
- package/lib/step/helper.js +4 -4
- package/lib/step/meta.js +3 -3
- package/lib/step/record.js +12 -4
- package/lib/store.js +72 -3
- package/lib/translation.js +2 -1
- package/lib/utils/loaderCheck.js +41 -3
- package/lib/utils/mask_data.js +2 -1
- package/lib/utils/pluginParser.js +151 -0
- package/lib/utils/trace.js +297 -0
- package/lib/utils/typescript.js +261 -49
- package/lib/utils.js +77 -3
- package/lib/workers.js +123 -17
- package/package.json +48 -43
- package/typings/index.d.ts +120 -9
- package/typings/promiseBasedTypes.d.ts +3243 -6057
- package/typings/types.d.ts +3541 -6506
- package/docs/webapi/amOnPage.mustache +0 -11
- package/docs/webapi/appendField.mustache +0 -11
- package/docs/webapi/attachFile.mustache +0 -12
- package/docs/webapi/blur.mustache +0 -18
- package/docs/webapi/checkOption.mustache +0 -13
- package/docs/webapi/clearCookie.mustache +0 -9
- package/docs/webapi/clearField.mustache +0 -9
- package/docs/webapi/click.mustache +0 -29
- package/docs/webapi/clickLink.mustache +0 -8
- package/docs/webapi/closeCurrentTab.mustache +0 -7
- package/docs/webapi/closeOtherTabs.mustache +0 -8
- package/docs/webapi/dontSee.mustache +0 -11
- package/docs/webapi/dontSeeCheckboxIsChecked.mustache +0 -10
- package/docs/webapi/dontSeeCookie.mustache +0 -8
- package/docs/webapi/dontSeeCurrentUrlEquals.mustache +0 -10
- package/docs/webapi/dontSeeElement.mustache +0 -8
- package/docs/webapi/dontSeeElementInDOM.mustache +0 -8
- package/docs/webapi/dontSeeInCurrentUrl.mustache +0 -4
- package/docs/webapi/dontSeeInField.mustache +0 -11
- package/docs/webapi/dontSeeInSource.mustache +0 -8
- package/docs/webapi/dontSeeInTitle.mustache +0 -8
- package/docs/webapi/dontSeeTraffic.mustache +0 -13
- package/docs/webapi/doubleClick.mustache +0 -13
- package/docs/webapi/downloadFile.mustache +0 -12
- package/docs/webapi/dragAndDrop.mustache +0 -9
- package/docs/webapi/dragSlider.mustache +0 -11
- package/docs/webapi/executeAsyncScript.mustache +0 -24
- package/docs/webapi/executeScript.mustache +0 -26
- package/docs/webapi/fillField.mustache +0 -16
- package/docs/webapi/flushNetworkTraffics.mustache +0 -5
- package/docs/webapi/focus.mustache +0 -13
- package/docs/webapi/forceClick.mustache +0 -28
- package/docs/webapi/forceRightClick.mustache +0 -18
- package/docs/webapi/grabAllWindowHandles.mustache +0 -7
- package/docs/webapi/grabAttributeFrom.mustache +0 -10
- package/docs/webapi/grabAttributeFromAll.mustache +0 -9
- package/docs/webapi/grabBrowserLogs.mustache +0 -9
- package/docs/webapi/grabCookie.mustache +0 -11
- package/docs/webapi/grabCssPropertyFrom.mustache +0 -11
- package/docs/webapi/grabCssPropertyFromAll.mustache +0 -10
- package/docs/webapi/grabCurrentUrl.mustache +0 -9
- package/docs/webapi/grabCurrentWindowHandle.mustache +0 -6
- package/docs/webapi/grabDataFromPerformanceTiming.mustache +0 -20
- package/docs/webapi/grabElementBoundingRect.mustache +0 -20
- package/docs/webapi/grabGeoLocation.mustache +0 -8
- package/docs/webapi/grabHTMLFrom.mustache +0 -10
- package/docs/webapi/grabHTMLFromAll.mustache +0 -9
- package/docs/webapi/grabNumberOfOpenTabs.mustache +0 -8
- package/docs/webapi/grabNumberOfVisibleElements.mustache +0 -9
- package/docs/webapi/grabPageScrollPosition.mustache +0 -8
- package/docs/webapi/grabPopupText.mustache +0 -5
- package/docs/webapi/grabRecordedNetworkTraffics.mustache +0 -10
- package/docs/webapi/grabSource.mustache +0 -8
- package/docs/webapi/grabTextFrom.mustache +0 -10
- package/docs/webapi/grabTextFromAll.mustache +0 -9
- package/docs/webapi/grabTitle.mustache +0 -8
- package/docs/webapi/grabValueFrom.mustache +0 -9
- package/docs/webapi/grabValueFromAll.mustache +0 -8
- package/docs/webapi/grabWebElement.mustache +0 -9
- package/docs/webapi/grabWebElements.mustache +0 -9
- package/docs/webapi/moveCursorTo.mustache +0 -12
- package/docs/webapi/openNewTab.mustache +0 -7
- package/docs/webapi/pressKey.mustache +0 -12
- package/docs/webapi/pressKeyDown.mustache +0 -12
- package/docs/webapi/pressKeyUp.mustache +0 -12
- package/docs/webapi/pressKeyWithKeyNormalization.mustache +0 -60
- package/docs/webapi/refreshPage.mustache +0 -6
- package/docs/webapi/resizeWindow.mustache +0 -6
- package/docs/webapi/rightClick.mustache +0 -14
- package/docs/webapi/saveElementScreenshot.mustache +0 -10
- package/docs/webapi/saveScreenshot.mustache +0 -12
- package/docs/webapi/say.mustache +0 -10
- package/docs/webapi/scrollIntoView.mustache +0 -11
- package/docs/webapi/scrollPageToBottom.mustache +0 -6
- package/docs/webapi/scrollPageToTop.mustache +0 -6
- package/docs/webapi/scrollTo.mustache +0 -12
- package/docs/webapi/see.mustache +0 -11
- package/docs/webapi/seeAttributesOnElements.mustache +0 -9
- package/docs/webapi/seeCheckboxIsChecked.mustache +0 -10
- package/docs/webapi/seeCookie.mustache +0 -8
- package/docs/webapi/seeCssPropertiesOnElements.mustache +0 -9
- package/docs/webapi/seeCurrentUrlEquals.mustache +0 -11
- package/docs/webapi/seeElement.mustache +0 -8
- package/docs/webapi/seeElementInDOM.mustache +0 -8
- package/docs/webapi/seeInCurrentUrl.mustache +0 -8
- package/docs/webapi/seeInField.mustache +0 -12
- package/docs/webapi/seeInPopup.mustache +0 -8
- package/docs/webapi/seeInSource.mustache +0 -7
- package/docs/webapi/seeInTitle.mustache +0 -8
- package/docs/webapi/seeNumberOfElements.mustache +0 -11
- package/docs/webapi/seeNumberOfVisibleElements.mustache +0 -10
- package/docs/webapi/seeTextEquals.mustache +0 -9
- package/docs/webapi/seeTitleEquals.mustache +0 -8
- package/docs/webapi/seeTraffic.mustache +0 -36
- package/docs/webapi/selectOption.mustache +0 -21
- package/docs/webapi/setCookie.mustache +0 -16
- package/docs/webapi/setGeoLocation.mustache +0 -12
- package/docs/webapi/startRecordingTraffic.mustache +0 -8
- package/docs/webapi/startRecordingWebSocketMessages.mustache +0 -8
- package/docs/webapi/stopRecordingTraffic.mustache +0 -5
- package/docs/webapi/stopRecordingWebSocketMessages.mustache +0 -7
- package/docs/webapi/switchTo.mustache +0 -9
- package/docs/webapi/switchToNextTab.mustache +0 -10
- package/docs/webapi/switchToPreviousTab.mustache +0 -10
- package/docs/webapi/type.mustache +0 -21
- package/docs/webapi/uncheckOption.mustache +0 -13
- package/docs/webapi/wait.mustache +0 -8
- package/docs/webapi/waitForClickable.mustache +0 -11
- package/docs/webapi/waitForCookie.mustache +0 -9
- package/docs/webapi/waitForDetached.mustache +0 -10
- package/docs/webapi/waitForDisabled.mustache +0 -6
- package/docs/webapi/waitForElement.mustache +0 -11
- package/docs/webapi/waitForEnabled.mustache +0 -6
- package/docs/webapi/waitForFunction.mustache +0 -17
- package/docs/webapi/waitForInvisible.mustache +0 -10
- package/docs/webapi/waitForNumberOfTabs.mustache +0 -9
- package/docs/webapi/waitForText.mustache +0 -13
- package/docs/webapi/waitForValue.mustache +0 -10
- package/docs/webapi/waitForVisible.mustache +0 -10
- package/docs/webapi/waitInUrl.mustache +0 -9
- package/docs/webapi/waitNumberOfVisibleElements.mustache +0 -10
- package/docs/webapi/waitToHide.mustache +0 -10
- package/docs/webapi/waitUrlEquals.mustache +0 -10
- package/lib/helper/AI.js +0 -214
- package/lib/helper/Mochawesome.js +0 -96
- package/lib/helper/extras/PlaywrightReactVueLocator.js +0 -52
- package/lib/helper/extras/React.js +0 -65
- package/lib/listener/enhancedGlobalRetry.js +0 -110
- package/lib/plugin/enhancedRetryFailedStep.js +0 -99
- package/lib/plugin/htmlReporter.js +0 -3648
- package/lib/plugin/stepByStepReport.js +0 -427
- package/lib/plugin/subtitles.js +0 -89
- package/lib/retryCoordinator.js +0 -207
|
@@ -0,0 +1,745 @@
|
|
|
1
|
+
---
|
|
2
|
+
permalink: /migration-4
|
|
3
|
+
title: Migrating from 3.x to 4.x
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Migrating from 3.x to 4.x
|
|
7
|
+
|
|
8
|
+
CodeceptJS 4.x is a major release. It moves the codebase from CommonJS to native ESM, drops several long-deprecated helpers and plugins, replaces legacy plugins with first-class APIs, and bumps most third-party dependencies.
|
|
9
|
+
|
|
10
|
+
> Migrate automatically! Install CodeceptJS skills `npx skills add codeceptjs/skills` and run `/codeceptjs-3-to-4-migration` in your coding agent
|
|
11
|
+
|
|
12
|
+
This guide tells you exactly what to change in your project to upgrade.
|
|
13
|
+
|
|
14
|
+
## 1. Update Node and Package
|
|
15
|
+
|
|
16
|
+
CodeceptJS 4.x supports Node 16+, but Node 20 or newer is recommended.
|
|
17
|
+
|
|
18
|
+
```bash
|
|
19
|
+
npm install codeceptjs@4
|
|
20
|
+
```
|
|
21
|
+
|
|
22
|
+
If you write tests in TypeScript, install `tsx`:
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
npm install --save-dev tsx
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
> 4.x replaces `ts-node/esm` with `tsx`. `ts-node/esm` is no longer recommended and emits a warning.
|
|
29
|
+
|
|
30
|
+
## 2. Switch Your Project to ESM
|
|
31
|
+
|
|
32
|
+
CodeceptJS 4.x ships as native ESM (`"type": "module"`). **Convert your project to ESM**.
|
|
33
|
+
Add to your `package.json`:
|
|
34
|
+
|
|
35
|
+
```json
|
|
36
|
+
{
|
|
37
|
+
"type": "module"
|
|
38
|
+
}
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
Then convert your config, page objects, and custom helpers to ESM (sections below).
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
### Convert Custom Helpers
|
|
45
|
+
|
|
46
|
+
3.x:
|
|
47
|
+
|
|
48
|
+
```js
|
|
49
|
+
const Helper = require('@codeceptjs/helper')
|
|
50
|
+
|
|
51
|
+
class MyHelper extends Helper {
|
|
52
|
+
doSomething() { /* ... */ }
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
module.exports = MyHelper
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
4.x:
|
|
59
|
+
|
|
60
|
+
```js
|
|
61
|
+
import Helper from '@codeceptjs/helper'
|
|
62
|
+
|
|
63
|
+
class MyHelper extends Helper {
|
|
64
|
+
doSomething() { /* ... */ }
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
export default MyHelper
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
### Convert Page Objects
|
|
71
|
+
|
|
72
|
+
Replace `module.exports = { ... }` with `export default { ... }`.
|
|
73
|
+
|
|
74
|
+
Page objects gain new lifecycle hooks in 4.x: `_before`, `_after`, `_afterSuite`. They run automatically around suites that include the page object.
|
|
75
|
+
|
|
76
|
+
### Convert Programmatic Usage
|
|
77
|
+
|
|
78
|
+
3.x:
|
|
79
|
+
|
|
80
|
+
```js
|
|
81
|
+
const { codecept, container, event } = require('codeceptjs')
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
4.x:
|
|
85
|
+
|
|
86
|
+
```js
|
|
87
|
+
import codeceptjs, { container, event } from 'codeceptjs'
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
`Container.create()` and `Config.load()` are now **async**. Await them:
|
|
91
|
+
|
|
92
|
+
```js
|
|
93
|
+
const config = await Config.load('./codecept.conf.js')
|
|
94
|
+
await Container.create(config, opts)
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## 3. Remove Helpers That No Longer Exist
|
|
98
|
+
|
|
99
|
+
| Removed helper | What to do |
|
|
100
|
+
|----------------|------------|
|
|
101
|
+
| `Nightmare` | Switch to `Playwright`, `Puppeteer`, or `WebDriver`. Nightmare is unmaintained; `Playwright` is the closest drop-in for headless flows. |
|
|
102
|
+
| `Protractor` | Switch to `Playwright` or `WebDriver`. Angular apps work without the Protractor-specific waits — use `waitForElement`/`waitForClickable`. |
|
|
103
|
+
| `TestCafe` | Switch to `Playwright`. |
|
|
104
|
+
| `AI` | Use the top-level `ai:` config option and the new `aiTrace` plugin. |
|
|
105
|
+
| `SoftExpectHelper` | Use the `hopeThat` effect instead — see below. |
|
|
106
|
+
| `Mochawesome` | Removed. Use the [Testomat.io Reporter](https://github.com/testomatio/reporter) HTML pipe for HTML reports — see below. |
|
|
107
|
+
|
|
108
|
+
`Container.STANDARD_ACTING_HELPERS` no longer lists `TestCafe`.
|
|
109
|
+
|
|
110
|
+
If you relied on a removed helper for behavior none of the built-in helpers cover, **write a custom helper**. A helper is a plain class extending `@codeceptjs/helper`; you can wrap any Node library and expose `I.*` actions. See [Custom Helpers](/helpers).
|
|
111
|
+
|
|
112
|
+
```js
|
|
113
|
+
import Helper from '@codeceptjs/helper'
|
|
114
|
+
|
|
115
|
+
class MyHelper extends Helper {
|
|
116
|
+
async doSomething() { /* wrap any library here */ }
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
export default MyHelper
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
### `SoftExpectHelper` → `hopeThat`
|
|
123
|
+
|
|
124
|
+
3.x shipped a `SoftExpectHelper` (`I.softAssert`, `I.softExpectEqual`, `I.flushSoftAssertions`, etc.) for soft assertions. It is gone in 4.x. Use the `hopeThat` effect — it works with **any** assertion that throws (built-in `I.see*`, your custom helper, `expect` from chai/jest, Node's `assert`).
|
|
125
|
+
|
|
126
|
+
3.x:
|
|
127
|
+
|
|
128
|
+
```js
|
|
129
|
+
helpers: { SoftExpectHelper: {} }
|
|
130
|
+
|
|
131
|
+
// in scenario
|
|
132
|
+
I.softExpectEqual(user.name, 'jon')
|
|
133
|
+
I.softExpectContain(emails, 'jon@doe.com')
|
|
134
|
+
I.flushSoftAssertions()
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
4.x:
|
|
138
|
+
|
|
139
|
+
```js
|
|
140
|
+
import { hopeThat } from 'codeceptjs/effects'
|
|
141
|
+
|
|
142
|
+
await hopeThat(() => assert.strictEqual(user.name, 'jon'))
|
|
143
|
+
await hopeThat(() => assert.ok(emails.includes('jon@doe.com')))
|
|
144
|
+
hopeThat.noErrors()
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
Each `hopeThat()` call records the failure as a note on the test and lets the scenario continue; `hopeThat.noErrors()` throws once at the end with every recorded failure if any happened. See [Effects: hopeThat](/effects#hopethat).
|
|
148
|
+
|
|
149
|
+
### `Mochawesome` → Testomat.io Reporter
|
|
150
|
+
|
|
151
|
+
3.x bundled a `Mochawesome` helper that pushed steps and screenshots into a [`mochawesome`](https://www.npmjs.com/package/mochawesome) Mocha report. The helper, the `mochawesome` dependency, and the worker-level report-dir wiring are all gone in 4.x.
|
|
152
|
+
|
|
153
|
+
For an HTML report, use the [Testomat.io Reporter](https://github.com/testomatio/reporter) with the HTML pipe — it includes steps, screenshots, videos, and traces, works under `--workers`, and needs no helper in your config. See [Reports](/reports).
|
|
154
|
+
|
|
155
|
+
3.x:
|
|
156
|
+
|
|
157
|
+
```js
|
|
158
|
+
helpers: { Mochawesome: { uniqueScreenshotNames: true } }
|
|
159
|
+
```
|
|
160
|
+
|
|
161
|
+
```bash
|
|
162
|
+
npx codeceptjs run --reporter mochawesome --reporter-options reportDir=output
|
|
163
|
+
```
|
|
164
|
+
|
|
165
|
+
4.x:
|
|
166
|
+
|
|
167
|
+
```bash
|
|
168
|
+
npm install --save-dev @testomatio/reporter
|
|
169
|
+
```
|
|
170
|
+
|
|
171
|
+
```js
|
|
172
|
+
// codecept.conf.js
|
|
173
|
+
plugins: {
|
|
174
|
+
testomatio: {
|
|
175
|
+
enabled: true,
|
|
176
|
+
require: '@testomatio/reporter/codecept',
|
|
177
|
+
html: true,
|
|
178
|
+
},
|
|
179
|
+
}
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
```bash
|
|
183
|
+
npx codeceptjs run
|
|
184
|
+
```
|
|
185
|
+
|
|
186
|
+
The HTML report is written to `output/report/` by default. See [Reports > HTML](/reports) for pipe options.
|
|
187
|
+
|
|
188
|
+
Reporting notes:
|
|
189
|
+
|
|
190
|
+
- **JUnit XML** (CI servers, GitHub Actions test tab): enable the [`junitReporter`](/plugins#junitreporter) plugin instead of `mocha-junit-reporter`. It includes CodeceptJS steps. See [Reports → JUnit XML](/reports#junit-xml).
|
|
191
|
+
- **Multiple Mocha reporters** via `mocha-multi` / `cmr` is **not recommended** in 4.x — the Testomat.io HTML pipe plus the `junitReporter` plugin cover the HTML + JUnit combination without chaining reporters.
|
|
192
|
+
|
|
193
|
+
#### Keeping Mochawesome (not recommended)
|
|
194
|
+
|
|
195
|
+
The `mochawesome` reporter itself is a stock Mocha reporter — it never depended on CodeceptJS bundling it, so it keeps working. Only the bundled **helper** (which embedded failure screenshots into the report) was removed. If you must stay on Mochawesome, you own that glue now.
|
|
196
|
+
|
|
197
|
+
**Report only — no screenshots embedded.** This works as-is:
|
|
198
|
+
|
|
199
|
+
```bash
|
|
200
|
+
npm install --save-dev mochawesome
|
|
201
|
+
npx codeceptjs run --reporter mochawesome --reporter-options reportDir=output
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
**Report with embedded failure screenshots.** Re-create the old helper as a project-local custom helper. This is a faithful port of the 3.x helper:
|
|
205
|
+
|
|
206
|
+
```js
|
|
207
|
+
// helpers/Mochawesome.js
|
|
208
|
+
import Helper from '@codeceptjs/helper'
|
|
209
|
+
import { createRequire } from 'module'
|
|
210
|
+
// ⚠️ Internal, NOT semver-stable subpaths. Pin your codeceptjs version —
|
|
211
|
+
// a future minor may move these. This coupling is why core dropped the helper.
|
|
212
|
+
import { clearString } from 'codeceptjs/lib/utils.js'
|
|
213
|
+
import { testToFileName } from 'codeceptjs/lib/mocha/test.js'
|
|
214
|
+
|
|
215
|
+
const addContext = createRequire(import.meta.url)('mochawesome/addContext')
|
|
216
|
+
|
|
217
|
+
class Mochawesome extends Helper {
|
|
218
|
+
constructor(config) {
|
|
219
|
+
super(config)
|
|
220
|
+
this.options = { uniqueScreenshotNames: false, disableScreenshots: false, ...config }
|
|
221
|
+
this.currentTest = ''
|
|
222
|
+
this.currentSuite = null
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
_beforeSuite(suite) {
|
|
226
|
+
this.currentSuite = suite
|
|
227
|
+
this.currentTest = ''
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
_before() {
|
|
231
|
+
if (this.currentSuite?.ctx) {
|
|
232
|
+
this.currentTest = { test: this.currentSuite.ctx.currentTest }
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
_test(test) {
|
|
237
|
+
this.currentTest = { test }
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
_failed(test) {
|
|
241
|
+
if (this.options.disableScreenshots) return
|
|
242
|
+
let fileName
|
|
243
|
+
if (test.ctx?.test?.type === 'hook') {
|
|
244
|
+
this.currentTest = { test: test.ctx.test }
|
|
245
|
+
test._retries = -1
|
|
246
|
+
fileName = clearString(`${test.title}_${this.currentTest.test.title}`)
|
|
247
|
+
} else {
|
|
248
|
+
this.currentTest = { test }
|
|
249
|
+
fileName = testToFileName(test)
|
|
250
|
+
}
|
|
251
|
+
if (this.options.uniqueScreenshotNames) {
|
|
252
|
+
fileName = testToFileName(test, { unique: true })
|
|
253
|
+
}
|
|
254
|
+
if (test._retries < 1 || test._retries === test.retryNum) {
|
|
255
|
+
return addContext(this.currentTest, `${fileName}.failed.png`)
|
|
256
|
+
}
|
|
257
|
+
}
|
|
258
|
+
|
|
259
|
+
// exposed as I.addMochawesomeContext(...) for manual attachments
|
|
260
|
+
addMochawesomeContext(context) {
|
|
261
|
+
if (this.currentTest === '') this.currentTest = { test: this.currentSuite.ctx.test }
|
|
262
|
+
return addContext(this.currentTest, context)
|
|
263
|
+
}
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
export default Mochawesome
|
|
267
|
+
```
|
|
268
|
+
|
|
269
|
+
Register it and run with the reporter:
|
|
270
|
+
|
|
271
|
+
```js
|
|
272
|
+
// codecept.conf.js
|
|
273
|
+
helpers: {
|
|
274
|
+
Mochawesome: {
|
|
275
|
+
require: './helpers/Mochawesome.js',
|
|
276
|
+
uniqueScreenshotNames: true,
|
|
277
|
+
},
|
|
278
|
+
}
|
|
279
|
+
```
|
|
280
|
+
|
|
281
|
+
```bash
|
|
282
|
+
npx codeceptjs run --reporter mochawesome --reporter-options reportDir=output
|
|
283
|
+
```
|
|
284
|
+
|
|
285
|
+
Two caveats this port cannot fully solve:
|
|
286
|
+
|
|
287
|
+
- The internal imports (`codeceptjs/lib/utils.js`, `codeceptjs/lib/mocha/test.js`) are reachable but **not part of the public API** — pin `codeceptjs` and re-test on upgrades.
|
|
288
|
+
- The 3.x `screenshot`/`screenshotOnFail` plugin read `helpers.Mochawesome.config.uniqueScreenshotNames` to keep the embedded reference and the saved screenshot file in sync. Core no longer does this. Set `uniqueScreenshotNames` to the **same value** on both this helper and the `screenshot` plugin, or the embedded filename and the saved file can diverge on retries.
|
|
289
|
+
|
|
290
|
+
### Custom Assertion Libraries
|
|
291
|
+
|
|
292
|
+
No code changes are required for chai, expect, jest-style matchers, or Node's `assert` — just import them in your test files. With `noGlobals: true`, they work the same as before.
|
|
293
|
+
|
|
294
|
+
Heads up on chai: 3.x pinned `chai@4`; 4.x devDep is `chai@6`, which is **ESM-only** and drops some legacy APIs. If you import chai in your tests, switch to `import { expect } from 'chai'` and verify your matchers still resolve.
|
|
295
|
+
|
|
296
|
+
## 4. Replace or Remove Plugins
|
|
297
|
+
|
|
298
|
+
| Removed plugin | Replacement |
|
|
299
|
+
|----------------|-------------|
|
|
300
|
+
| `autoLogin` | **`auth` plugin** — see [Authorization](/auth). |
|
|
301
|
+
| `tryTo` | `import { tryTo } from 'codeceptjs/effects'` |
|
|
302
|
+
| `retryTo` | `import { retryTo } from 'codeceptjs/effects'` |
|
|
303
|
+
| `eachElement` | `import { eachElement } from 'codeceptjs/els'` |
|
|
304
|
+
| `commentStep` | `import step from 'codeceptjs/steps'` then `step.section('name')` / `step.endSection()` |
|
|
305
|
+
| `fakerTransform` | Import `@faker-js/faker` directly in tests. |
|
|
306
|
+
| `enhancedRetryFailedStep` | Merged into `retryFailedStep`. Rename in config. |
|
|
307
|
+
| `allure` | Use [@testomatio/reporter](https://testomat.io). |
|
|
308
|
+
| `htmlReporter` | Use the [Testomat.io Reporter](https://github.com/testomatio/reporter) HTML pipe — see [Reports](/reports). |
|
|
309
|
+
| `wdio` | Configure WebdriverIO services directly in `helpers.WebDriver`. |
|
|
310
|
+
| `selenoid` | Run Selenoid externally. |
|
|
311
|
+
| `standardActingHelpers` | No longer needed; the list lives in core. |
|
|
312
|
+
|
|
313
|
+
### `autoLogin` → `auth`
|
|
314
|
+
|
|
315
|
+
3.x:
|
|
316
|
+
|
|
317
|
+
```js
|
|
318
|
+
plugins: {
|
|
319
|
+
autoLogin: {
|
|
320
|
+
enabled: true,
|
|
321
|
+
saveToFile: true,
|
|
322
|
+
inject: 'login',
|
|
323
|
+
users: { admin: { login, check, fetch } },
|
|
324
|
+
},
|
|
325
|
+
}
|
|
326
|
+
```
|
|
327
|
+
|
|
328
|
+
4.x:
|
|
329
|
+
|
|
330
|
+
```js
|
|
331
|
+
plugins: {
|
|
332
|
+
auth: {
|
|
333
|
+
enabled: true,
|
|
334
|
+
users: {
|
|
335
|
+
admin: {
|
|
336
|
+
login: (I) => { /* ... */ },
|
|
337
|
+
check: (I) => { /* ... */ },
|
|
338
|
+
},
|
|
339
|
+
},
|
|
340
|
+
},
|
|
341
|
+
}
|
|
342
|
+
```
|
|
343
|
+
|
|
344
|
+
Inject `login` and call `login('admin')` — same as before.
|
|
345
|
+
|
|
346
|
+
### Renamed Plugins
|
|
347
|
+
|
|
348
|
+
4.x unifies four plugins (`screenshot`, `pause`, `aiTrace`, `heal`) under a shared `on=` parameter. The old names live on as deprecated aliases that emit a warning and forward to the new plugin.
|
|
349
|
+
|
|
350
|
+
| Old plugin | New plugin | Notes |
|
|
351
|
+
| :------------------ | :------------------------------- | :------------------------------------------------- |
|
|
352
|
+
| `screenshotOnFail` | `screenshot` | Default `on='fail'`, same behavior |
|
|
353
|
+
| `pauseOnFail` | `pause` | Default `on='fail'`, same behavior |
|
|
354
|
+
| `stepByStepReport` | `screenshot` with `slides: true` | Use `on=step` to capture every step |
|
|
355
|
+
|
|
356
|
+
### New Plugins You Can Enable
|
|
357
|
+
|
|
358
|
+
- **`aiTrace`** — captures failure traces (DOM, console, network, screenshots) for AI debugging. See [AI Trace](/aitrace).
|
|
359
|
+
- **`pause`** — pauses execution on a chosen event or on failure. See [Debugging](/debugging).
|
|
360
|
+
- **`heal`** — self-heals failing steps with AI; narrow with `on=file|url`.
|
|
361
|
+
|
|
362
|
+
## 5. Update Removed and Changed APIs
|
|
363
|
+
|
|
364
|
+
### AI Config Now Uses Vercel AI SDK
|
|
365
|
+
|
|
366
|
+
3.x required a hand-written `request` function that called your provider's SDK directly. 4.x replaces this with [Vercel AI SDK](https://ai-sdk.dev) — pass a `model` and CodeceptJS handles the calls.
|
|
367
|
+
|
|
368
|
+
Install the SDK and the provider package you want:
|
|
369
|
+
|
|
370
|
+
```bash
|
|
371
|
+
npm install ai @ai-sdk/openai
|
|
372
|
+
# or @ai-sdk/anthropic, @ai-sdk/google, @ai-sdk/mistral, @ai-sdk/groq, @ai-sdk/xai, @ai-sdk/azure, @ai-sdk/cohere
|
|
373
|
+
```
|
|
374
|
+
|
|
375
|
+
3.x:
|
|
376
|
+
|
|
377
|
+
```js
|
|
378
|
+
ai: {
|
|
379
|
+
request: async messages => {
|
|
380
|
+
const OpenAI = require('openai')
|
|
381
|
+
const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY })
|
|
382
|
+
const completion = await openai.chat.completions.create({
|
|
383
|
+
model: 'gpt-3.5-turbo',
|
|
384
|
+
messages,
|
|
385
|
+
})
|
|
386
|
+
return completion?.choices[0]?.message?.content
|
|
387
|
+
},
|
|
388
|
+
}
|
|
389
|
+
```
|
|
390
|
+
|
|
391
|
+
4.x:
|
|
392
|
+
|
|
393
|
+
```js
|
|
394
|
+
import { openai } from '@ai-sdk/openai'
|
|
395
|
+
|
|
396
|
+
export default {
|
|
397
|
+
ai: {
|
|
398
|
+
model: openai('gpt-5'),
|
|
399
|
+
},
|
|
400
|
+
}
|
|
401
|
+
```
|
|
402
|
+
|
|
403
|
+
The same shape works for every supported provider — swap `openai('gpt-5')` for `anthropic('claude-sonnet-4-6')`, `google('gemini-1.5-flash')`, etc. API keys still come from environment variables (`OPENAI_API_KEY`, `ANTHROPIC_API_KEY`, `GOOGLE_GENERATIVE_AI_API_KEY`, ...).
|
|
404
|
+
|
|
405
|
+
The `request` function is no longer supported. Delete it from your config.
|
|
406
|
+
|
|
407
|
+
See [Testing with AI](/ai) for the full provider list and prompt customization.
|
|
408
|
+
|
|
409
|
+
### JSON Schema Validation: Joi → Zod
|
|
410
|
+
|
|
411
|
+
`I.seeResponseMatchesJsonSchema()` (from the `JSONResponse` helper) now validates with [Zod](https://zod.dev) instead of [Joi](https://joi.dev). Joi is gone from the dependency tree; Zod is bundled.
|
|
412
|
+
|
|
413
|
+
Rewrite your schemas:
|
|
414
|
+
|
|
415
|
+
3.x:
|
|
416
|
+
|
|
417
|
+
```js
|
|
418
|
+
const Joi = require('joi')
|
|
419
|
+
|
|
420
|
+
I.seeResponseMatchesJsonSchema(Joi.object().keys({
|
|
421
|
+
name: Joi.string().required(),
|
|
422
|
+
email: Joi.string().email().required(),
|
|
423
|
+
age: Joi.number().integer().min(0),
|
|
424
|
+
}))
|
|
425
|
+
```
|
|
426
|
+
|
|
427
|
+
4.x:
|
|
428
|
+
|
|
429
|
+
```js
|
|
430
|
+
import { z } from 'zod'
|
|
431
|
+
|
|
432
|
+
I.seeResponseMatchesJsonSchema(z.object({
|
|
433
|
+
name: z.string(),
|
|
434
|
+
email: z.string().email(),
|
|
435
|
+
age: z.number().int().min(0),
|
|
436
|
+
}))
|
|
437
|
+
```
|
|
438
|
+
|
|
439
|
+
Or pass a callback that receives `z`:
|
|
440
|
+
|
|
441
|
+
```js
|
|
442
|
+
I.seeResponseMatchesJsonSchema(z => z.object({
|
|
443
|
+
name: z.string(),
|
|
444
|
+
id: z.number(),
|
|
445
|
+
}))
|
|
446
|
+
```
|
|
447
|
+
|
|
448
|
+
Common rewrites:
|
|
449
|
+
|
|
450
|
+
| Joi | Zod |
|
|
451
|
+
|-----|-----|
|
|
452
|
+
| `Joi.object().keys({...})` | `z.object({...})` |
|
|
453
|
+
| `Joi.string().required()` | `z.string()` (required by default) |
|
|
454
|
+
| `Joi.string().email()` | `z.string().email()` |
|
|
455
|
+
| `Joi.number().integer()` | `z.number().int()` |
|
|
456
|
+
| `Joi.array().items(...)` | `z.array(...)` |
|
|
457
|
+
| `Joi.string().optional()` | `z.string().optional()` |
|
|
458
|
+
| `Joi.date()` | `z.string().datetime()` or `z.date()` |
|
|
459
|
+
| `Joi.alternatives().try(a, b)` | `z.union([a, b])` |
|
|
460
|
+
|
|
461
|
+
Uninstall `joi` from your project if you only used it for CodeceptJS schemas:
|
|
462
|
+
|
|
463
|
+
```bash
|
|
464
|
+
npm uninstall joi
|
|
465
|
+
```
|
|
466
|
+
|
|
467
|
+
### `restart: 'browser'` removed (Playwright)
|
|
468
|
+
|
|
469
|
+
Use one of:
|
|
470
|
+
|
|
471
|
+
- `restart: 'session'` — reset session per test (default)
|
|
472
|
+
- `restart: 'context'` — new browser context per test
|
|
473
|
+
- `restart: 'keep'` — keep one browser across tests
|
|
474
|
+
|
|
475
|
+
### Custom Locator Strategy removed (Playwright)
|
|
476
|
+
|
|
477
|
+
The `customLocators` strategy registration in Playwright config is removed. Use the `customLocator` plugin or built-in ARIA locators (`{ role: 'button', name: 'Submit' }`).
|
|
478
|
+
|
|
479
|
+
### React and Vue Locators removed
|
|
480
|
+
|
|
481
|
+
The `react` component locator and the bare-string `_react=`/`_vue=` Playwright selectors are removed from the Playwright, Puppeteer, and WebDriver helpers. The `resq` dependency is dropped.
|
|
482
|
+
|
|
483
|
+
```js
|
|
484
|
+
// 3.x (removed)
|
|
485
|
+
I.click({ react: 'SubmitButton' })
|
|
486
|
+
I.seeElement({ react: 'Alert' })
|
|
487
|
+
I.fillField({ react: 'EmailInput' }, 'a@b.com')
|
|
488
|
+
```
|
|
489
|
+
|
|
490
|
+
They relied on `resq`, which is unmaintained, supports only React 16, reads React's private internal tree, and breaks under production minification. There is no working path for React 17, 18, or 19.
|
|
491
|
+
|
|
492
|
+
Use [ARIA locators](/locators#aria-locators) instead — they match how a user perceives the page and survive refactoring and minification:
|
|
493
|
+
|
|
494
|
+
```js
|
|
495
|
+
// 4.x
|
|
496
|
+
I.click({ role: 'button', name: 'Submit' })
|
|
497
|
+
I.seeElement('[role=alert]')
|
|
498
|
+
I.fillField('Email', 'a@b.com')
|
|
499
|
+
```
|
|
500
|
+
|
|
501
|
+
For a component that renders no stable role, label, or text, add a `data-testid` in the JSX and locate by it: `I.click('[data-testid="submit"]')`.
|
|
502
|
+
|
|
503
|
+
### `I.retry()` and `I.limitTime()` removed
|
|
504
|
+
|
|
505
|
+
Both were deprecated in 3.x and are **removed in 4.x**. They configured the *next* step through a chained call; the replacement is the step options API — pass a `step.*` config as the **last argument** of the step itself.
|
|
506
|
+
|
|
507
|
+
```js
|
|
508
|
+
import step from 'codeceptjs/steps'
|
|
509
|
+
|
|
510
|
+
// 3.x (removed) → 4.x
|
|
511
|
+
I.retry(3).click('Submit') // I.click('Submit', step.retry(3))
|
|
512
|
+
I.limitTime(10).fillField('Email', 'a@b.c') // I.fillField('Email', 'a@b.c', step.timeout(10))
|
|
513
|
+
```
|
|
514
|
+
|
|
515
|
+
`step.*` configs are also composable with the other step options:
|
|
516
|
+
|
|
517
|
+
```js
|
|
518
|
+
I.click('Add', step.opts({ elementIndex: 2 }))
|
|
519
|
+
```
|
|
520
|
+
|
|
521
|
+
The behavior is unchanged — the option applies only to the step it is attached to, not to subsequent steps (this also fixes the 3.x footgun where `I.retry()` could leak retry settings onto the following step). `recorder.retry()` is unaffected and remains available for custom helpers.
|
|
522
|
+
|
|
523
|
+
### `within` Is Now an Effect
|
|
524
|
+
|
|
525
|
+
In 3.x, `within(...)` was a global statement available everywhere. In 4.x it's an effect alongside `tryTo`, `retryTo`, and `hopeThat`. Under `noGlobals: true` you must import it:
|
|
526
|
+
|
|
527
|
+
```js
|
|
528
|
+
import { within } from 'codeceptjs/effects'
|
|
529
|
+
|
|
530
|
+
await within('.signup-form', () => {
|
|
531
|
+
I.fillField('Email', 'a@b.c')
|
|
532
|
+
I.click('Submit')
|
|
533
|
+
})
|
|
534
|
+
```
|
|
535
|
+
|
|
536
|
+
`within` returns a Promise — `await` it whenever you need its return value or want subsequent steps to wait for it. The same applies to `session`, which moved from global to a regular import (`import { session } from 'codeceptjs'`).
|
|
537
|
+
|
|
538
|
+
### Effects and Assertions Are Subpath Imports
|
|
539
|
+
|
|
540
|
+
```js
|
|
541
|
+
import { within, tryTo, retryTo, hopeThat } from 'codeceptjs/effects'
|
|
542
|
+
import { hopeThat } from 'codeceptjs/assertions'
|
|
543
|
+
import { eachElement, element, expectElement } from 'codeceptjs/els'
|
|
544
|
+
import step from 'codeceptjs/steps'
|
|
545
|
+
import store from 'codeceptjs/store'
|
|
546
|
+
```
|
|
547
|
+
|
|
548
|
+
`tryTo` and `hopeThat` now return `Promise<boolean>`. The 3.x generic `Promise<T | false>` signature is gone.
|
|
549
|
+
|
|
550
|
+
`hopeThat.noErrors()` is new — call it once at the end of a scenario to fail the test if any soft assertion failed.
|
|
551
|
+
|
|
552
|
+
### Globals Are Deprecated — `noGlobals: true` Is the New Default
|
|
553
|
+
|
|
554
|
+
Up to 3.x, almost everything was global: `Feature`, `Scenario`, `Before`, `pause`, `within`, `session`, `secret`, `Helper`, `actor`, `inject`, `share`, `locate`, `DataTable`, `Given`/`When`/`Then`, `codecept_dir`, `output_dir`.
|
|
555
|
+
|
|
556
|
+
In 4.x:
|
|
557
|
+
|
|
558
|
+
- `npx codeceptjs init` writes `noGlobals: true` into new configs.
|
|
559
|
+
- Projects without `noGlobals` set keep the old behavior but print a deprecation warning on every run:
|
|
560
|
+
|
|
561
|
+
> Global functions are deprecated. Use `import { Helper, pause, within, session } from "codeceptjs"` instead. Set `noGlobals: true` in config to disable globals.
|
|
562
|
+
|
|
563
|
+
To silence the warning, set `noGlobals: true`:
|
|
564
|
+
|
|
565
|
+
```js
|
|
566
|
+
// codecept.conf.js
|
|
567
|
+
export const config = {
|
|
568
|
+
noGlobals: true,
|
|
569
|
+
// ...
|
|
570
|
+
}
|
|
571
|
+
```
|
|
572
|
+
|
|
573
|
+
What changes when `noGlobals: true`:
|
|
574
|
+
|
|
575
|
+
| Symbol | With `noGlobals: true` |
|
|
576
|
+
|--------|------------------------|
|
|
577
|
+
| `Feature`, `Scenario`, `xFeature`, `xScenario`, `BeforeSuite`, `AfterSuite`, `Before`, `After`, `Background`, `BeforeAll`, `AfterAll` | **Still work in test files** — Mocha injects these into the test context. No import needed. |
|
|
578
|
+
| `pause()`, `inject()`, `share()` | **Still global.** Always available (with or without `noGlobals`) — they're the standard wiring/debugging entry points and run before any import would resolve. `pause` and `inject` are also exported from `codeceptjs` if you prefer explicit imports. |
|
|
579
|
+
| `codecept_dir`, `output_dir` | **Still global** (kept for backward compatibility with external plugins). |
|
|
580
|
+
| `within`, `session`, `secret`, `locate`, `dataTable`, `actor`, `codeceptjs` | Import from `codeceptjs`. |
|
|
581
|
+
| `Helper` (base class) | Import from `@codeceptjs/helper`. |
|
|
582
|
+
| `Given`, `When`, `Then`, `And`, `DefineParameterType` (BDD step definitions) | Available as globals **inside Gherkin step definition files** (CodeceptJS scope-injects them while loading the step files). No import needed. |
|
|
583
|
+
|
|
584
|
+
Imports for the new style:
|
|
585
|
+
|
|
586
|
+
```js
|
|
587
|
+
import { within, session, secret, locate, dataTable, actor } from 'codeceptjs'
|
|
588
|
+
import Helper from '@codeceptjs/helper'
|
|
589
|
+
```
|
|
590
|
+
|
|
591
|
+
Test files written for 3.x keep working until you flip the flag.
|
|
592
|
+
|
|
593
|
+
### `wait*` Methods Resolve Relative URLs
|
|
594
|
+
|
|
595
|
+
`waitInUrl`, `waitUrlEquals`, and `waitCurrentPathEquals` now resolve a relative path against the helper's configured `url` before comparing. In 3.x a literal substring match against `window.location.href` would fail for relative paths.
|
|
596
|
+
|
|
597
|
+
```js
|
|
598
|
+
// helpers: { Playwright: { url: 'https://app.example.com' } }
|
|
599
|
+
|
|
600
|
+
I.waitUrlEquals('/dashboard') // matches https://app.example.com/dashboard
|
|
601
|
+
I.waitInUrl('/users') // matches any URL containing /users
|
|
602
|
+
```
|
|
603
|
+
|
|
604
|
+
`waitUrlEquals` error messages now include the actual URL the page was on when the wait timed out — easier to diagnose `/dashboard` vs `/dashboard?session=expired`.
|
|
605
|
+
|
|
606
|
+
## 6. Adopt New Behaviors
|
|
607
|
+
|
|
608
|
+
### Strict Mode
|
|
609
|
+
|
|
610
|
+
Playwright, Puppeteer, and WebDriver helpers support `strict: true`. Any locator that matches more than one element throws `MultipleElementsFound` instead of silently picking the first match.
|
|
611
|
+
|
|
612
|
+
```js
|
|
613
|
+
helpers: {
|
|
614
|
+
Playwright: { url: '...', strict: true },
|
|
615
|
+
}
|
|
616
|
+
```
|
|
617
|
+
|
|
618
|
+
Per-step alternative: `I.click('a', step.opts({ exact: true }))`.
|
|
619
|
+
|
|
620
|
+
The error includes a `fetchDetails()` method that prints XPaths and HTML for every match.
|
|
621
|
+
|
|
622
|
+
### Element Index
|
|
623
|
+
|
|
624
|
+
Pick a specific match without writing a more specific locator:
|
|
625
|
+
|
|
626
|
+
```js
|
|
627
|
+
I.click('a', step.opts({ elementIndex: 2 }))
|
|
628
|
+
I.click('a', step.opts({ elementIndex: 'last' }))
|
|
629
|
+
I.fillField('input', 'x', step.opts({ elementIndex: -1 }))
|
|
630
|
+
```
|
|
631
|
+
|
|
632
|
+
### Unfocused Element Detection
|
|
633
|
+
|
|
634
|
+
`I.type()` and `I.pressKey()` throw `NonFocusedType` if no element has focus. Click or focus the field first.
|
|
635
|
+
|
|
636
|
+
### Context Parameter on Form Methods
|
|
637
|
+
|
|
638
|
+
`appendField`, `clearField`, `attachFile`, and `moveCursorTo` accept an optional second context argument, matching `fillField` and `click`.
|
|
639
|
+
|
|
640
|
+
### Other New Methods
|
|
641
|
+
|
|
642
|
+
- `I.seeCurrentPathEquals(path)` / `I.dontSeeCurrentPathEquals(path)` — compare the path ignoring query strings.
|
|
643
|
+
- `I.waitCurrentPathEquals(path, sec?)` — wait until the path matches.
|
|
644
|
+
- `I.seeFileDownloaded(name)`
|
|
645
|
+
- `I.clickXY(locator?, x, y)` — click at coordinates, either page-relative or element-relative.
|
|
646
|
+
- `I.grabAriaSnapshot(locator?)` — capture an accessibility-tree snapshot for the page or a region (Playwright).
|
|
647
|
+
- `I.grabWebElement(locator)` / `I.grabWebElements(locator)` — return helper-agnostic `WebElement` wrappers.
|
|
648
|
+
- `attachFile` — supports drag-and-drop dropzones.
|
|
649
|
+
- `fillField` — supports rich text editors (CKEditor, ProseMirror, etc.).
|
|
650
|
+
- BDD: `But` keyword is recognized.
|
|
651
|
+
|
|
652
|
+
### CLI Plugin Arguments
|
|
653
|
+
|
|
654
|
+
`-p` accepts colon-chained arguments, so plugins can be enabled and configured from the command line without editing config:
|
|
655
|
+
|
|
656
|
+
```bash
|
|
657
|
+
npx codeceptjs run -p pause # pause on every failure
|
|
658
|
+
npx codeceptjs run -p pause:on=url:pattern=/checkout/* # pause when URL matches
|
|
659
|
+
npx codeceptjs run -p screenshot:on=step # screenshot every step
|
|
660
|
+
npx codeceptjs run -p browser:show # force visible browser
|
|
661
|
+
npx codeceptjs run -p browser:browser=firefox:windowSize=1024x768
|
|
662
|
+
npx codeceptjs run -p plugin1,plugin2:arg # multiple plugins
|
|
663
|
+
```
|
|
664
|
+
|
|
665
|
+
Each argument after the plugin name is a `key=value` pair. `:` separates pairs. `;` is an inline alternative for visually grouping related pairs (e.g. `path=...;line=...`). Reserved keys: `on`, `path`, `line`, `pattern`.
|
|
666
|
+
|
|
667
|
+
The `browser` plugin is new in 4.x — it overrides the active browser helper (Playwright, Puppeteer, WebDriver, Appium) from the CLI, useful for ad-hoc local runs and CI matrices. See [Commands](/commands).
|
|
668
|
+
|
|
669
|
+
The old `-p all` magic keyword is gone (it conflicted with the colon syntax). Enable specific plugins explicitly: `-p pluginA,pluginB`.
|
|
670
|
+
|
|
671
|
+
### Workers: Events and Plugin Scope
|
|
672
|
+
|
|
673
|
+
Two notable changes for parallel runs:
|
|
674
|
+
|
|
675
|
+
- **Event dispatcher fires inside workers.** In 3.x, listeners attached to `event.dispatcher` only saw events from the main process. In 4.x, plugins and listeners observe per-test events inside each worker, so things like custom reporters and screenshot hooks work the same in single-process and worker modes ([#5464](https://github.com/codeceptjs/CodeceptJS/pull/5464)).
|
|
676
|
+
- **`runInParent` / `runInMain` plugin option.** Set to `false` on plugins that should only run inside worker children (default is `true`). Useful for plugins that aggregate per-worker state from the parent.
|
|
677
|
+
|
|
678
|
+
```js
|
|
679
|
+
plugins: {
|
|
680
|
+
myReporter: {
|
|
681
|
+
enabled: true,
|
|
682
|
+
runInParent: false, // only run in worker children
|
|
683
|
+
},
|
|
684
|
+
}
|
|
685
|
+
```
|
|
686
|
+
|
|
687
|
+
### TypeScript Improvements
|
|
688
|
+
|
|
689
|
+
If you write tests in TypeScript, 4.x is significantly better:
|
|
690
|
+
|
|
691
|
+
- **`tsx` loader** instead of `ts-node/esm` — faster startup, better ESM compatibility. Install `tsx` (optional peer dep). `ts-node/esm` still works but emits a deprecation warning.
|
|
692
|
+
- **Error stack traces** point at `.ts` source lines, not transpiled output.
|
|
693
|
+
- **`__dirname` / `__filename`** are injected for TypeScript files that use them (ESM normally hides these globals).
|
|
694
|
+
- **Path aliases** from `tsconfig.json` (`paths`) are resolved at runtime — `import x from '@/utils'` works without extra runtime config.
|
|
695
|
+
- **`codecept.conf.ts`** supports top-level `await` via dynamic imports.
|
|
696
|
+
- **`steps_file.ts`** and TypeScript support objects load correctly across files.
|
|
697
|
+
|
|
698
|
+
## 7. Update Dependency Versions
|
|
699
|
+
|
|
700
|
+
If your project depends on these directly, check for breakage:
|
|
701
|
+
|
|
702
|
+
| Package | 3.x | 4.x |
|
|
703
|
+
|---------|-----|-----|
|
|
704
|
+
| `chai` | ^4 | ^6 (ESM-only) |
|
|
705
|
+
| `chai-as-promised` | 7 | 8 (ESM-only) |
|
|
706
|
+
| `@cucumber/gherkin` | 35 | 38 |
|
|
707
|
+
| `@cucumber/messages` | 29 | 32 |
|
|
708
|
+
| `chokidar` | 4 | 5 |
|
|
709
|
+
| `commander` | 11 | 14 |
|
|
710
|
+
| `@faker-js/faker` | 9 | 10 |
|
|
711
|
+
| `webdriverio` | 9.12 | 9.23 |
|
|
712
|
+
| `puppeteer` | 24.15 | 24.36 |
|
|
713
|
+
| `electron` | 38 | 40 |
|
|
714
|
+
| `typescript` | 5.8 | 5.9 |
|
|
715
|
+
| `testcafe` | 3.7.2 | **removed** |
|
|
716
|
+
| `inquirer-test` | 2.0.1 | **removed** |
|
|
717
|
+
| `joi` | 18 | **removed** — use `zod` |
|
|
718
|
+
| `resq` | 1.11 | **removed** — `react`/`vue` locators dropped; use ARIA locators |
|
|
719
|
+
| `zod` | — | added (^4) — schema validation in `JSONResponse` |
|
|
720
|
+
| `tsx` | — | added as optional peer |
|
|
721
|
+
| `@modelcontextprotocol/sdk` | — | added |
|
|
722
|
+
| `@testomatio/reporter` | — | added |
|
|
723
|
+
|
|
724
|
+
## 8. New Capabilities Worth Knowing
|
|
725
|
+
|
|
726
|
+
You don't need these to upgrade, but they unlock new workflows:
|
|
727
|
+
|
|
728
|
+
- **MCP server** — `bin/mcp-server.js` (also installed as `codeceptjs-mcp`) exposes CodeceptJS to AI agents through Model Context Protocol. See [MCP](/mcp).
|
|
729
|
+
- **WebElement wrapper** — `grabWebElements()` returns helper-agnostic `WebElement` instances with a unified API.
|
|
730
|
+
- **ARIA-first locators** — `{ role: 'button', name: 'Submit' }` works in Playwright, Puppeteer, and WebDriver. The `role` type is now first-class in `Locator`. See [Locators](/locators#aria-locators).
|
|
731
|
+
- **Locator DSL** — `locate(...)` gains `.withClass()`, `.not()` negation, raw-predicate helpers, and a `role` selector type.
|
|
732
|
+
- **Workers** — the `event` dispatcher fires inside worker processes, so listeners and plugins observe parallel runs the same way they observe single-process runs.
|
|
733
|
+
- **Path normalization** — file-path handling is normalized cross-platform; tests authored on Windows run unchanged on Linux/CI.
|
|
734
|
+
- **Test metadata** — the `Scenario` callback receives a `test` object with `test.tags`, `test.artifacts`, `test.meta`, and `test.notes` for custom reporting.
|
|
735
|
+
- **Security** — the `emptyFolder` utility (used by output cleanup) no longer shells out via `rm -rf`, closing a command-injection vector ([#5191](https://github.com/codeceptjs/CodeceptJS/pull/5191)).
|
|
736
|
+
|
|
737
|
+
## 9. Verify the Upgrade
|
|
738
|
+
|
|
739
|
+
1. `npx codeceptjs check` — surfaces config issues.
|
|
740
|
+
2. `npx codeceptjs run --debug` on a small smoke suite. Confirm the run starts and steps execute.
|
|
741
|
+
3. `npx codeceptjs run --workers 2` — confirm parallel execution.
|
|
742
|
+
4. TypeScript users: run with `tsx` installed and confirm error stack traces point at `.ts` files.
|
|
743
|
+
5. If you removed `autoLogin`: confirm sessions restore under the `auth` plugin.
|
|
744
|
+
6. If you used `tryTo` / `retryTo` / `eachElement` plugins: grep your tests for the old globals and switch to subpath imports.
|
|
745
|
+
7. CI: bump the Node version to 20+ if you were on 18 or below.
|