codeceptjs 4.0.0-rc.2 → 4.0.0-rc.20

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.
Files changed (294) hide show
  1. package/README.md +39 -27
  2. package/bin/codecept.js +15 -2
  3. package/bin/codeceptq.js +49 -0
  4. package/bin/mcp-server.js +1187 -0
  5. package/docs/advanced.md +201 -0
  6. package/docs/agents.md +159 -0
  7. package/docs/ai.md +537 -0
  8. package/docs/aitrace.md +266 -0
  9. package/docs/api.md +332 -0
  10. package/docs/assertions.md +415 -0
  11. package/docs/auth.md +318 -0
  12. package/docs/basics.md +424 -0
  13. package/docs/bdd.md +539 -0
  14. package/docs/best.md +240 -0
  15. package/docs/bootstrap.md +132 -0
  16. package/docs/commands.md +352 -0
  17. package/docs/community-helpers.md +63 -0
  18. package/docs/configuration.md +230 -0
  19. package/docs/continuous-integration.md +497 -0
  20. package/docs/custom-helpers.md +297 -0
  21. package/docs/data.md +448 -0
  22. package/docs/debugging.md +332 -0
  23. package/docs/detox.md +235 -0
  24. package/docs/docker.md +136 -0
  25. package/docs/effects.md +179 -0
  26. package/docs/element-based-testing.md +295 -0
  27. package/docs/element-selection.md +125 -0
  28. package/docs/els.md +328 -0
  29. package/docs/examples.md +161 -0
  30. package/docs/heal.md +213 -0
  31. package/docs/helpers/ApiDataFactory.md +267 -0
  32. package/docs/helpers/Appium.md +1405 -0
  33. package/docs/helpers/Detox.md +665 -0
  34. package/docs/helpers/ExpectHelper.md +275 -0
  35. package/docs/helpers/FileSystem.md +152 -0
  36. package/docs/helpers/GraphQL.md +152 -0
  37. package/docs/helpers/GraphQLDataFactory.md +226 -0
  38. package/docs/helpers/JSONResponse.md +255 -0
  39. package/docs/helpers/Mochawesome.md +8 -0
  40. package/docs/helpers/MockRequest.md +377 -0
  41. package/docs/helpers/MockServer.md +212 -0
  42. package/docs/helpers/Playwright.md +2969 -0
  43. package/docs/helpers/Polly.md +44 -0
  44. package/docs/helpers/Protractor.md +1769 -0
  45. package/docs/helpers/Puppeteer-firefox.md +86 -0
  46. package/docs/helpers/Puppeteer.md +2690 -0
  47. package/docs/helpers/REST.md +289 -0
  48. package/docs/helpers/SoftExpectHelper.md +352 -0
  49. package/docs/helpers/WebDriver.md +2682 -0
  50. package/docs/hooks.md +339 -0
  51. package/docs/index.md +111 -0
  52. package/docs/installation.md +83 -0
  53. package/docs/internal-api.md +265 -0
  54. package/docs/internal-test-server.md +89 -0
  55. package/docs/locators.md +355 -0
  56. package/docs/mcp.md +485 -0
  57. package/docs/migration-4.md +556 -0
  58. package/docs/mobile.md +338 -0
  59. package/docs/pageobjects.md +399 -0
  60. package/docs/parallel.md +585 -0
  61. package/docs/playwright.md +714 -0
  62. package/docs/plugins.md +866 -0
  63. package/docs/puppeteer.md +314 -0
  64. package/docs/quickstart.md +120 -0
  65. package/docs/react.md +70 -0
  66. package/docs/reports.md +483 -0
  67. package/docs/retry.md +274 -0
  68. package/docs/secrets.md +150 -0
  69. package/docs/sessions.md +80 -0
  70. package/docs/shadow.md +68 -0
  71. package/docs/test-structure.md +275 -0
  72. package/docs/timeouts.md +183 -0
  73. package/docs/translation.md +247 -0
  74. package/docs/tutorial.md +271 -0
  75. package/docs/typescript.md +374 -0
  76. package/docs/web-element.md +251 -0
  77. package/docs/webdriver.md +708 -0
  78. package/docs/within.md +55 -0
  79. package/lib/ai.js +3 -2
  80. package/lib/aria.js +260 -0
  81. package/lib/assertions.js +18 -0
  82. package/lib/codecept.js +26 -23
  83. package/lib/command/check.js +2 -1
  84. package/lib/command/dryRun.js +24 -5
  85. package/lib/command/generate.js +2 -0
  86. package/lib/command/gherkin/snippets.js +5 -4
  87. package/lib/command/init.js +248 -269
  88. package/lib/command/list.js +150 -10
  89. package/lib/command/query.js +218 -0
  90. package/lib/command/run-multiple.js +2 -0
  91. package/lib/command/run-workers.js +2 -0
  92. package/lib/command/run.js +1 -1
  93. package/lib/command/workers/runTests.js +10 -10
  94. package/lib/config.js +77 -4
  95. package/lib/container.js +114 -17
  96. package/lib/effects.js +17 -0
  97. package/lib/element/WebElement.js +246 -2
  98. package/lib/els.js +12 -6
  99. package/lib/globals.js +32 -19
  100. package/lib/heal.js +4 -3
  101. package/lib/helper/ApiDataFactory.js +2 -1
  102. package/lib/helper/Appium.js +8 -8
  103. package/lib/helper/FileSystem.js +3 -2
  104. package/lib/helper/GraphQLDataFactory.js +2 -1
  105. package/lib/helper/Playwright.js +228 -162
  106. package/lib/helper/Puppeteer.js +208 -76
  107. package/lib/helper/WebDriver.js +173 -68
  108. package/lib/helper/errors/MultipleElementsFound.js +27 -110
  109. package/lib/helper/errors/NonFocusedType.js +8 -0
  110. package/lib/helper/extras/Download.js +45 -0
  111. package/lib/helper/extras/PlaywrightReactVueLocator.js +45 -36
  112. package/lib/helper/extras/elementSelection.js +58 -0
  113. package/lib/helper/extras/focusCheck.js +43 -0
  114. package/lib/helper/extras/richTextEditor.js +178 -0
  115. package/lib/helper/scripts/dropFile.js +11 -0
  116. package/lib/history.js +3 -2
  117. package/lib/html.js +103 -16
  118. package/lib/index.js +9 -1
  119. package/lib/listener/config.js +6 -4
  120. package/lib/listener/emptyRun.js +2 -1
  121. package/lib/listener/globalRetry.js +32 -6
  122. package/lib/listener/helpers.js +4 -1
  123. package/lib/listener/mocha.js +2 -1
  124. package/lib/listener/pageobjects.js +43 -0
  125. package/lib/listener/result.js +3 -2
  126. package/lib/locator.js +126 -3
  127. package/lib/mocha/cli.js +14 -2
  128. package/lib/mocha/factory.js +7 -2
  129. package/lib/mocha/inject.js +1 -1
  130. package/lib/mocha/scenarioConfig.js +2 -1
  131. package/lib/mocha/ui.js +5 -6
  132. package/lib/parser.js +2 -2
  133. package/lib/pause.js +38 -4
  134. package/lib/plugin/aiTrace.js +453 -0
  135. package/lib/plugin/analyze.js +1 -1
  136. package/lib/plugin/auth.js +3 -3
  137. package/lib/plugin/browser.js +77 -0
  138. package/lib/plugin/expose.js +159 -0
  139. package/lib/plugin/heal.js +44 -1
  140. package/lib/plugin/pageInfo.js +53 -49
  141. package/lib/plugin/pause.js +131 -0
  142. package/lib/plugin/pauseOnFail.js +10 -34
  143. package/lib/plugin/retryFailedStep.js +28 -19
  144. package/lib/plugin/screencast.js +287 -0
  145. package/lib/plugin/screenshot.js +563 -0
  146. package/lib/plugin/screenshotOnFail.js +8 -171
  147. package/lib/rerun.js +2 -1
  148. package/lib/result.js +2 -1
  149. package/lib/step/base.js +3 -2
  150. package/lib/step/config.js +15 -2
  151. package/lib/step/record.js +2 -2
  152. package/lib/store.js +72 -3
  153. package/lib/translation.js +2 -1
  154. package/lib/utils/mask_data.js +2 -1
  155. package/lib/utils/pluginParser.js +151 -0
  156. package/lib/utils/trace.js +297 -0
  157. package/lib/utils.js +77 -3
  158. package/lib/workers.js +52 -22
  159. package/package.json +19 -13
  160. package/typings/index.d.ts +19 -5
  161. package/docs/webapi/amOnPage.mustache +0 -11
  162. package/docs/webapi/appendField.mustache +0 -11
  163. package/docs/webapi/attachFile.mustache +0 -12
  164. package/docs/webapi/blur.mustache +0 -18
  165. package/docs/webapi/checkOption.mustache +0 -13
  166. package/docs/webapi/clearCookie.mustache +0 -9
  167. package/docs/webapi/clearField.mustache +0 -9
  168. package/docs/webapi/click.mustache +0 -29
  169. package/docs/webapi/clickLink.mustache +0 -8
  170. package/docs/webapi/closeCurrentTab.mustache +0 -7
  171. package/docs/webapi/closeOtherTabs.mustache +0 -8
  172. package/docs/webapi/dontSee.mustache +0 -11
  173. package/docs/webapi/dontSeeCheckboxIsChecked.mustache +0 -10
  174. package/docs/webapi/dontSeeCookie.mustache +0 -8
  175. package/docs/webapi/dontSeeCurrentPathEquals.mustache +0 -10
  176. package/docs/webapi/dontSeeCurrentUrlEquals.mustache +0 -10
  177. package/docs/webapi/dontSeeElement.mustache +0 -8
  178. package/docs/webapi/dontSeeElementInDOM.mustache +0 -8
  179. package/docs/webapi/dontSeeInCurrentUrl.mustache +0 -4
  180. package/docs/webapi/dontSeeInField.mustache +0 -11
  181. package/docs/webapi/dontSeeInSource.mustache +0 -8
  182. package/docs/webapi/dontSeeInTitle.mustache +0 -8
  183. package/docs/webapi/dontSeeTraffic.mustache +0 -13
  184. package/docs/webapi/doubleClick.mustache +0 -13
  185. package/docs/webapi/downloadFile.mustache +0 -12
  186. package/docs/webapi/dragAndDrop.mustache +0 -9
  187. package/docs/webapi/dragSlider.mustache +0 -11
  188. package/docs/webapi/executeAsyncScript.mustache +0 -24
  189. package/docs/webapi/executeScript.mustache +0 -26
  190. package/docs/webapi/fillField.mustache +0 -16
  191. package/docs/webapi/flushNetworkTraffics.mustache +0 -5
  192. package/docs/webapi/focus.mustache +0 -13
  193. package/docs/webapi/forceClick.mustache +0 -28
  194. package/docs/webapi/forceRightClick.mustache +0 -18
  195. package/docs/webapi/grabAllWindowHandles.mustache +0 -7
  196. package/docs/webapi/grabAttributeFrom.mustache +0 -10
  197. package/docs/webapi/grabAttributeFromAll.mustache +0 -9
  198. package/docs/webapi/grabBrowserLogs.mustache +0 -9
  199. package/docs/webapi/grabCookie.mustache +0 -11
  200. package/docs/webapi/grabCssPropertyFrom.mustache +0 -11
  201. package/docs/webapi/grabCssPropertyFromAll.mustache +0 -10
  202. package/docs/webapi/grabCurrentUrl.mustache +0 -9
  203. package/docs/webapi/grabCurrentWindowHandle.mustache +0 -6
  204. package/docs/webapi/grabDataFromPerformanceTiming.mustache +0 -20
  205. package/docs/webapi/grabElementBoundingRect.mustache +0 -20
  206. package/docs/webapi/grabGeoLocation.mustache +0 -8
  207. package/docs/webapi/grabHTMLFrom.mustache +0 -10
  208. package/docs/webapi/grabHTMLFromAll.mustache +0 -9
  209. package/docs/webapi/grabNumberOfOpenTabs.mustache +0 -8
  210. package/docs/webapi/grabNumberOfVisibleElements.mustache +0 -9
  211. package/docs/webapi/grabPageScrollPosition.mustache +0 -8
  212. package/docs/webapi/grabPopupText.mustache +0 -5
  213. package/docs/webapi/grabRecordedNetworkTraffics.mustache +0 -10
  214. package/docs/webapi/grabSource.mustache +0 -8
  215. package/docs/webapi/grabTextFrom.mustache +0 -10
  216. package/docs/webapi/grabTextFromAll.mustache +0 -9
  217. package/docs/webapi/grabTitle.mustache +0 -8
  218. package/docs/webapi/grabValueFrom.mustache +0 -9
  219. package/docs/webapi/grabValueFromAll.mustache +0 -8
  220. package/docs/webapi/grabWebElement.mustache +0 -9
  221. package/docs/webapi/grabWebElements.mustache +0 -9
  222. package/docs/webapi/moveCursorTo.mustache +0 -12
  223. package/docs/webapi/openNewTab.mustache +0 -7
  224. package/docs/webapi/pressKey.mustache +0 -12
  225. package/docs/webapi/pressKeyDown.mustache +0 -12
  226. package/docs/webapi/pressKeyUp.mustache +0 -12
  227. package/docs/webapi/pressKeyWithKeyNormalization.mustache +0 -60
  228. package/docs/webapi/refreshPage.mustache +0 -6
  229. package/docs/webapi/resizeWindow.mustache +0 -6
  230. package/docs/webapi/rightClick.mustache +0 -14
  231. package/docs/webapi/saveElementScreenshot.mustache +0 -10
  232. package/docs/webapi/saveScreenshot.mustache +0 -12
  233. package/docs/webapi/say.mustache +0 -10
  234. package/docs/webapi/scrollIntoView.mustache +0 -11
  235. package/docs/webapi/scrollPageToBottom.mustache +0 -6
  236. package/docs/webapi/scrollPageToTop.mustache +0 -6
  237. package/docs/webapi/scrollTo.mustache +0 -12
  238. package/docs/webapi/see.mustache +0 -11
  239. package/docs/webapi/seeAttributesOnElements.mustache +0 -9
  240. package/docs/webapi/seeCheckboxIsChecked.mustache +0 -10
  241. package/docs/webapi/seeCookie.mustache +0 -8
  242. package/docs/webapi/seeCssPropertiesOnElements.mustache +0 -9
  243. package/docs/webapi/seeCurrentPathEquals.mustache +0 -10
  244. package/docs/webapi/seeCurrentUrlEquals.mustache +0 -11
  245. package/docs/webapi/seeElement.mustache +0 -8
  246. package/docs/webapi/seeElementInDOM.mustache +0 -8
  247. package/docs/webapi/seeInCurrentUrl.mustache +0 -8
  248. package/docs/webapi/seeInField.mustache +0 -12
  249. package/docs/webapi/seeInPopup.mustache +0 -8
  250. package/docs/webapi/seeInSource.mustache +0 -7
  251. package/docs/webapi/seeInTitle.mustache +0 -8
  252. package/docs/webapi/seeNumberOfElements.mustache +0 -11
  253. package/docs/webapi/seeNumberOfVisibleElements.mustache +0 -10
  254. package/docs/webapi/seeTextEquals.mustache +0 -9
  255. package/docs/webapi/seeTitleEquals.mustache +0 -8
  256. package/docs/webapi/seeTraffic.mustache +0 -36
  257. package/docs/webapi/selectOption.mustache +0 -21
  258. package/docs/webapi/setCookie.mustache +0 -16
  259. package/docs/webapi/setGeoLocation.mustache +0 -12
  260. package/docs/webapi/startRecordingTraffic.mustache +0 -8
  261. package/docs/webapi/startRecordingWebSocketMessages.mustache +0 -8
  262. package/docs/webapi/stopRecordingTraffic.mustache +0 -5
  263. package/docs/webapi/stopRecordingWebSocketMessages.mustache +0 -7
  264. package/docs/webapi/switchTo.mustache +0 -9
  265. package/docs/webapi/switchToNextTab.mustache +0 -10
  266. package/docs/webapi/switchToPreviousTab.mustache +0 -10
  267. package/docs/webapi/type.mustache +0 -21
  268. package/docs/webapi/uncheckOption.mustache +0 -13
  269. package/docs/webapi/wait.mustache +0 -8
  270. package/docs/webapi/waitForClickable.mustache +0 -11
  271. package/docs/webapi/waitForCookie.mustache +0 -9
  272. package/docs/webapi/waitForDetached.mustache +0 -10
  273. package/docs/webapi/waitForDisabled.mustache +0 -6
  274. package/docs/webapi/waitForElement.mustache +0 -11
  275. package/docs/webapi/waitForEnabled.mustache +0 -6
  276. package/docs/webapi/waitForFunction.mustache +0 -17
  277. package/docs/webapi/waitForInvisible.mustache +0 -10
  278. package/docs/webapi/waitForNumberOfTabs.mustache +0 -9
  279. package/docs/webapi/waitForText.mustache +0 -13
  280. package/docs/webapi/waitForValue.mustache +0 -10
  281. package/docs/webapi/waitForVisible.mustache +0 -10
  282. package/docs/webapi/waitInUrl.mustache +0 -9
  283. package/docs/webapi/waitNumberOfVisibleElements.mustache +0 -10
  284. package/docs/webapi/waitToHide.mustache +0 -10
  285. package/docs/webapi/waitUrlEquals.mustache +0 -10
  286. package/lib/helper/AI.js +0 -214
  287. package/lib/listener/enhancedGlobalRetry.js +0 -110
  288. package/lib/plugin/enhancedRetryFailedStep.js +0 -99
  289. package/lib/plugin/htmlReporter.js +0 -3648
  290. package/lib/plugin/stepByStepReport.js +0 -427
  291. package/lib/plugin/subtitles.js +0 -89
  292. package/lib/retryCoordinator.js +0 -207
  293. package/typings/promiseBasedTypes.d.ts +0 -9469
  294. package/typings/types.d.ts +0 -11402
@@ -0,0 +1,556 @@
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
+ This guide tells you exactly what to change in your project to upgrade.
11
+
12
+ ## 1. Update Node and Package
13
+
14
+ CodeceptJS 4.x supports Node 16+, but Node 20 or newer is recommended.
15
+
16
+ ```bash
17
+ npm install codeceptjs@4
18
+ ```
19
+
20
+ If you write tests in TypeScript, install `tsx`:
21
+
22
+ ```bash
23
+ npm install --save-dev tsx
24
+ ```
25
+
26
+ > 4.x replaces `ts-node/esm` with `tsx`. `ts-node/esm` is no longer recommended and emits a warning.
27
+
28
+ ## 2. Switch Your Project to ESM
29
+
30
+ CodeceptJS 4.x ships as native ESM (`"type": "module"`). **Convert your project to ESM**.
31
+ Add to your `package.json`:
32
+
33
+ ```json
34
+ {
35
+ "type": "module"
36
+ }
37
+ ```
38
+
39
+ Then convert your config, page objects, and custom helpers to ESM (sections below).
40
+
41
+
42
+ ### Convert Custom Helpers
43
+
44
+ 3.x:
45
+
46
+ ```js
47
+ const Helper = require('@codeceptjs/helper')
48
+
49
+ class MyHelper extends Helper {
50
+ doSomething() { /* ... */ }
51
+ }
52
+
53
+ module.exports = MyHelper
54
+ ```
55
+
56
+ 4.x:
57
+
58
+ ```js
59
+ import Helper from '@codeceptjs/helper'
60
+
61
+ class MyHelper extends Helper {
62
+ doSomething() { /* ... */ }
63
+ }
64
+
65
+ export default MyHelper
66
+ ```
67
+
68
+ ### Convert Page Objects
69
+
70
+ Replace `module.exports = { ... }` with `export default { ... }`.
71
+
72
+ Page objects gain new lifecycle hooks in 4.x: `_before`, `_after`, `_afterSuite`. They run automatically around suites that include the page object.
73
+
74
+ ### Convert Programmatic Usage
75
+
76
+ 3.x:
77
+
78
+ ```js
79
+ const { codecept, container, event } = require('codeceptjs')
80
+ ```
81
+
82
+ 4.x:
83
+
84
+ ```js
85
+ import codeceptjs, { container, event } from 'codeceptjs'
86
+ ```
87
+
88
+ `Container.create()` and `Config.load()` are now **async**. Await them:
89
+
90
+ ```js
91
+ const config = await Config.load('./codecept.conf.js')
92
+ await Container.create(config, opts)
93
+ ```
94
+
95
+ ## 3. Remove Helpers That No Longer Exist
96
+
97
+ | Removed helper | What to do |
98
+ |----------------|------------|
99
+ | `Nightmare` | Switch to `Playwright`, `Puppeteer`, or `WebDriver`. |
100
+ | `Protractor` | Switch to `Playwright` or `WebDriver`. |
101
+ | `TestCafe` | Switch to `Playwright`. |
102
+ | `AI` | Use the top-level `ai:` config option and the new `aiTrace` plugin. |
103
+ | `SoftExpectHelper` | Use the `hopeThat` effect instead — see below. |
104
+
105
+ `Container.STANDARD_ACTING_HELPERS` no longer lists `TestCafe`.
106
+
107
+ ### `SoftExpectHelper` → `hopeThat`
108
+
109
+ 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`).
110
+
111
+ 3.x:
112
+
113
+ ```js
114
+ helpers: { SoftExpectHelper: {} }
115
+
116
+ // in scenario
117
+ I.softExpectEqual(user.name, 'jon')
118
+ I.softExpectContain(emails, 'jon@doe.com')
119
+ I.flushSoftAssertions()
120
+ ```
121
+
122
+ 4.x:
123
+
124
+ ```js
125
+ import { hopeThat } from 'codeceptjs/effects'
126
+
127
+ await hopeThat(() => assert.strictEqual(user.name, 'jon'))
128
+ await hopeThat(() => assert.ok(emails.includes('jon@doe.com')))
129
+ hopeThat.noErrors()
130
+ ```
131
+
132
+ 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).
133
+
134
+ ### Custom Assertion Libraries
135
+
136
+ 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.
137
+
138
+ 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.
139
+
140
+ ## 4. Replace or Remove Plugins
141
+
142
+ | Removed plugin | Replacement |
143
+ |----------------|-------------|
144
+ | `autoLogin` | **`auth` plugin** — see [Authorization](/auth). |
145
+ | `tryTo` | `import { tryTo } from 'codeceptjs/effects'` |
146
+ | `retryTo` | `import { retryTo } from 'codeceptjs/effects'` |
147
+ | `eachElement` | `import { eachElement } from 'codeceptjs/els'` |
148
+ | `commentStep` | `import step from 'codeceptjs/steps'` then `step.section('name')` / `step.endSection()` |
149
+ | `fakerTransform` | Import `@faker-js/faker` directly in tests. |
150
+ | `enhancedRetryFailedStep` | Merged into `retryFailedStep`. Rename in config. |
151
+ | `allure` | Use [@testomatio/reporter](https://testomat.io) or Mochawesome. |
152
+ | `htmlReporter` | Use an external reporter. |
153
+ | `wdio` | Configure WebdriverIO services directly in `helpers.WebDriver`. |
154
+ | `selenoid` | Run Selenoid externally. |
155
+ | `standardActingHelpers` | No longer needed; the list lives in core. |
156
+
157
+ ### `autoLogin` → `auth`
158
+
159
+ 3.x:
160
+
161
+ ```js
162
+ plugins: {
163
+ autoLogin: {
164
+ enabled: true,
165
+ saveToFile: true,
166
+ inject: 'login',
167
+ users: { admin: { login, check, fetch } },
168
+ },
169
+ }
170
+ ```
171
+
172
+ 4.x:
173
+
174
+ ```js
175
+ plugins: {
176
+ auth: {
177
+ enabled: true,
178
+ users: {
179
+ admin: {
180
+ login: (I) => { /* ... */ },
181
+ check: (I) => { /* ... */ },
182
+ },
183
+ },
184
+ },
185
+ }
186
+ ```
187
+
188
+ Inject `login` and call `login('admin')` — same as before.
189
+
190
+ ### Renamed Plugins
191
+
192
+ 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.
193
+
194
+ | Old plugin | New plugin | Notes |
195
+ | :------------------ | :------------------------------- | :------------------------------------------------- |
196
+ | `screenshotOnFail` | `screenshot` | Default `on='fail'`, same behavior |
197
+ | `pauseOnFail` | `pause` | Default `on='fail'`, same behavior |
198
+ | `stepByStepReport` | `screenshot` with `slides: true` | Use `on=step` to capture every step |
199
+
200
+ ### New Plugins You Can Enable
201
+
202
+ - **`aiTrace`** — captures failure traces (DOM, console, network, screenshots) for AI debugging. See [AI Trace](/aitrace).
203
+ - **`pause`** — pauses execution on a chosen event or on failure. See [Debugging](/debugging).
204
+ - **`heal`** — self-heals failing steps with AI; narrow with `on=file|url`.
205
+
206
+ ## 5. Update Removed and Changed APIs
207
+
208
+ ### AI Config Now Uses Vercel AI SDK
209
+
210
+ 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.
211
+
212
+ Install the SDK and the provider package you want:
213
+
214
+ ```bash
215
+ npm install ai @ai-sdk/openai
216
+ # or @ai-sdk/anthropic, @ai-sdk/google, @ai-sdk/mistral, @ai-sdk/groq, @ai-sdk/xai, @ai-sdk/azure, @ai-sdk/cohere
217
+ ```
218
+
219
+ 3.x:
220
+
221
+ ```js
222
+ ai: {
223
+ request: async messages => {
224
+ const OpenAI = require('openai')
225
+ const openai = new OpenAI({ apiKey: process.env.OPENAI_API_KEY })
226
+ const completion = await openai.chat.completions.create({
227
+ model: 'gpt-3.5-turbo',
228
+ messages,
229
+ })
230
+ return completion?.choices[0]?.message?.content
231
+ },
232
+ }
233
+ ```
234
+
235
+ 4.x:
236
+
237
+ ```js
238
+ import { openai } from '@ai-sdk/openai'
239
+
240
+ export default {
241
+ ai: {
242
+ model: openai('gpt-5'),
243
+ },
244
+ }
245
+ ```
246
+
247
+ 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`, ...).
248
+
249
+ The `request` function is no longer supported. Delete it from your config.
250
+
251
+ See [Testing with AI](/ai) for the full provider list and prompt customization.
252
+
253
+ ### JSON Schema Validation: Joi → Zod
254
+
255
+ `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.
256
+
257
+ Rewrite your schemas:
258
+
259
+ 3.x:
260
+
261
+ ```js
262
+ const Joi = require('joi')
263
+
264
+ I.seeResponseMatchesJsonSchema(Joi.object().keys({
265
+ name: Joi.string().required(),
266
+ email: Joi.string().email().required(),
267
+ age: Joi.number().integer().min(0),
268
+ }))
269
+ ```
270
+
271
+ 4.x:
272
+
273
+ ```js
274
+ import { z } from 'zod'
275
+
276
+ I.seeResponseMatchesJsonSchema(z.object({
277
+ name: z.string(),
278
+ email: z.string().email(),
279
+ age: z.number().int().min(0),
280
+ }))
281
+ ```
282
+
283
+ Or pass a callback that receives `z`:
284
+
285
+ ```js
286
+ I.seeResponseMatchesJsonSchema(z => z.object({
287
+ name: z.string(),
288
+ id: z.number(),
289
+ }))
290
+ ```
291
+
292
+ Common rewrites:
293
+
294
+ | Joi | Zod |
295
+ |-----|-----|
296
+ | `Joi.object().keys({...})` | `z.object({...})` |
297
+ | `Joi.string().required()` | `z.string()` (required by default) |
298
+ | `Joi.string().email()` | `z.string().email()` |
299
+ | `Joi.number().integer()` | `z.number().int()` |
300
+ | `Joi.array().items(...)` | `z.array(...)` |
301
+ | `Joi.string().optional()` | `z.string().optional()` |
302
+ | `Joi.date()` | `z.string().datetime()` or `z.date()` |
303
+ | `Joi.alternatives().try(a, b)` | `z.union([a, b])` |
304
+
305
+ Uninstall `joi` from your project if you only used it for CodeceptJS schemas:
306
+
307
+ ```bash
308
+ npm uninstall joi
309
+ ```
310
+
311
+ ### `restart: 'browser'` removed (Playwright)
312
+
313
+ Use one of:
314
+
315
+ - `restart: 'session'` — reset session per test (default)
316
+ - `restart: 'context'` — new browser context per test
317
+ - `restart: 'keep'` — keep one browser across tests
318
+
319
+ ### Custom Locator Strategy removed (Playwright)
320
+
321
+ The `customLocators` strategy registration in Playwright config is removed. Use the `customLocator` plugin or built-in ARIA locators (`{ role: 'button', name: 'Submit' }`).
322
+
323
+ ### `I.retry()` is deprecated
324
+
325
+ Use the step options API:
326
+
327
+ ```js
328
+ import step from 'codeceptjs/steps'
329
+
330
+ I.click('Submit', step.retry(3))
331
+ I.fillField('Email', 'a@b.c', step.timeout(10))
332
+ I.click('Add', step.opts({ elementIndex: 2 }))
333
+ ```
334
+
335
+ ### `within` Is Now an Effect
336
+
337
+ 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:
338
+
339
+ ```js
340
+ import { within } from 'codeceptjs/effects'
341
+
342
+ await within('.signup-form', () => {
343
+ I.fillField('Email', 'a@b.c')
344
+ I.click('Submit')
345
+ })
346
+ ```
347
+
348
+ `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'`).
349
+
350
+ ### Effects and Assertions Are Subpath Imports
351
+
352
+ ```js
353
+ import { within, tryTo, retryTo, hopeThat } from 'codeceptjs/effects'
354
+ import { hopeThat } from 'codeceptjs/assertions'
355
+ import { eachElement, element, expectElement } from 'codeceptjs/els'
356
+ import step from 'codeceptjs/steps'
357
+ import store from 'codeceptjs/store'
358
+ ```
359
+
360
+ `tryTo` and `hopeThat` now return `Promise<boolean>`. The 3.x generic `Promise<T | false>` signature is gone.
361
+
362
+ `hopeThat.noErrors()` is new — call it once at the end of a scenario to fail the test if any soft assertion failed.
363
+
364
+ ### Globals Are Deprecated — `noGlobals: true` Is the New Default
365
+
366
+ 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`.
367
+
368
+ In 4.x:
369
+
370
+ - `npx codeceptjs init` writes `noGlobals: true` into new configs.
371
+ - Projects without `noGlobals` set keep the old behavior but print a deprecation warning on every run:
372
+
373
+ > Global functions are deprecated. Use `import { Helper, pause, within, session } from "codeceptjs"` instead. Set `noGlobals: true` in config to disable globals.
374
+
375
+ To silence the warning, set `noGlobals: true`:
376
+
377
+ ```js
378
+ // codecept.conf.js
379
+ export const config = {
380
+ noGlobals: true,
381
+ // ...
382
+ }
383
+ ```
384
+
385
+ What changes when `noGlobals: true`:
386
+
387
+ | Symbol | With `noGlobals: true` |
388
+ |--------|------------------------|
389
+ | `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. |
390
+ | `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. |
391
+ | `codecept_dir`, `output_dir` | **Still global** (kept for backward compatibility with external plugins). |
392
+ | `within`, `session`, `secret`, `locate`, `dataTable`, `actor`, `codeceptjs` | Import from `codeceptjs`. |
393
+ | `Helper` (base class) | Import from `@codeceptjs/helper`. |
394
+ | `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. |
395
+
396
+ Imports for the new style:
397
+
398
+ ```js
399
+ import { within, session, secret, locate, dataTable, actor } from 'codeceptjs'
400
+ import Helper from '@codeceptjs/helper'
401
+ ```
402
+
403
+ Test files written for 3.x keep working until you flip the flag.
404
+
405
+ ### `wait*` Methods Resolve Relative URLs
406
+
407
+ `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.
408
+
409
+ ```js
410
+ // helpers: { Playwright: { url: 'https://app.example.com' } }
411
+
412
+ I.waitUrlEquals('/dashboard') // matches https://app.example.com/dashboard
413
+ I.waitInUrl('/users') // matches any URL containing /users
414
+ ```
415
+
416
+ `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`.
417
+
418
+ ## 6. Adopt New Behaviors
419
+
420
+ ### Strict Mode
421
+
422
+ 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.
423
+
424
+ ```js
425
+ helpers: {
426
+ Playwright: { url: '...', strict: true },
427
+ }
428
+ ```
429
+
430
+ Per-step alternative: `I.click('a', step.opts({ exact: true }))`.
431
+
432
+ The error includes a `fetchDetails()` method that prints XPaths and HTML for every match.
433
+
434
+ ### Element Index
435
+
436
+ Pick a specific match without writing a more specific locator:
437
+
438
+ ```js
439
+ I.click('a', step.opts({ elementIndex: 2 }))
440
+ I.click('a', step.opts({ elementIndex: 'last' }))
441
+ I.fillField('input', 'x', step.opts({ elementIndex: -1 }))
442
+ ```
443
+
444
+ ### Unfocused Element Detection
445
+
446
+ `I.type()` and `I.pressKey()` throw `NonFocusedType` if no element has focus. Click or focus the field first.
447
+
448
+ ### Context Parameter on Form Methods
449
+
450
+ `appendField`, `clearField`, `attachFile`, and `moveCursorTo` accept an optional second context argument, matching `fillField` and `click`.
451
+
452
+ ### Other New Methods
453
+
454
+ - `I.seeCurrentPathEquals(path)` / `I.dontSeeCurrentPathEquals(path)` — compare the path ignoring query strings.
455
+ - `I.waitCurrentPathEquals(path, sec?)` — wait until the path matches.
456
+ - `I.seeFileDownloaded(name)`
457
+ - `I.clickXY(locator?, x, y)` — click at coordinates, either page-relative or element-relative.
458
+ - `I.grabAriaSnapshot(locator?)` — capture an accessibility-tree snapshot for the page or a region (Playwright).
459
+ - `I.grabWebElement(locator)` / `I.grabWebElements(locator)` — return helper-agnostic `WebElement` wrappers.
460
+ - `attachFile` — supports drag-and-drop dropzones.
461
+ - `fillField` — supports rich text editors (CKEditor, ProseMirror, etc.).
462
+ - BDD: `But` keyword is recognized.
463
+
464
+ ### CLI Plugin Arguments
465
+
466
+ `-p` accepts colon-chained arguments, so plugins can be enabled and configured from the command line without editing config:
467
+
468
+ ```bash
469
+ npx codeceptjs run -p pause # pause on every failure
470
+ npx codeceptjs run -p pause:on=url:pattern=/checkout/* # pause when URL matches
471
+ npx codeceptjs run -p screenshot:on=step # screenshot every step
472
+ npx codeceptjs run -p browser:show # force visible browser
473
+ npx codeceptjs run -p browser:browser=firefox:windowSize=1024x768
474
+ npx codeceptjs run -p plugin1,plugin2:arg # multiple plugins
475
+ ```
476
+
477
+ 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`.
478
+
479
+ 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).
480
+
481
+ The old `-p all` magic keyword is gone (it conflicted with the colon syntax). Enable specific plugins explicitly: `-p pluginA,pluginB`.
482
+
483
+ ### Workers: Events and Plugin Scope
484
+
485
+ Two notable changes for parallel runs:
486
+
487
+ - **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)).
488
+ - **`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.
489
+
490
+ ```js
491
+ plugins: {
492
+ myReporter: {
493
+ enabled: true,
494
+ runInParent: false, // only run in worker children
495
+ },
496
+ }
497
+ ```
498
+
499
+ ### TypeScript Improvements
500
+
501
+ If you write tests in TypeScript, 4.x is significantly better:
502
+
503
+ - **`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.
504
+ - **Error stack traces** point at `.ts` source lines, not transpiled output.
505
+ - **`__dirname` / `__filename`** are injected for TypeScript files that use them (ESM normally hides these globals).
506
+ - **Path aliases** from `tsconfig.json` (`paths`) are resolved at runtime — `import x from '@/utils'` works without extra runtime config.
507
+ - **`codecept.conf.ts`** supports top-level `await` via dynamic imports.
508
+ - **`steps_file.ts`** and TypeScript support objects load correctly across files.
509
+
510
+ ## 7. Update Dependency Versions
511
+
512
+ If your project depends on these directly, check for breakage:
513
+
514
+ | Package | 3.x | 4.x |
515
+ |---------|-----|-----|
516
+ | `chai` | ^4 | ^6 (ESM-only) |
517
+ | `chai-as-promised` | 7 | 8 (ESM-only) |
518
+ | `@cucumber/gherkin` | 35 | 38 |
519
+ | `@cucumber/messages` | 29 | 32 |
520
+ | `chokidar` | 4 | 5 |
521
+ | `commander` | 11 | 14 |
522
+ | `@faker-js/faker` | 9 | 10 |
523
+ | `webdriverio` | 9.12 | 9.23 |
524
+ | `puppeteer` | 24.15 | 24.36 |
525
+ | `electron` | 38 | 40 |
526
+ | `typescript` | 5.8 | 5.9 |
527
+ | `testcafe` | 3.7.2 | **removed** |
528
+ | `inquirer-test` | 2.0.1 | **removed** |
529
+ | `joi` | 18 | **removed** — use `zod` |
530
+ | `zod` | — | added (^4) — schema validation in `JSONResponse` |
531
+ | `tsx` | — | added as optional peer |
532
+ | `@modelcontextprotocol/sdk` | — | added |
533
+ | `@testomatio/reporter` | — | added |
534
+
535
+ ## 8. New Capabilities Worth Knowing
536
+
537
+ You don't need these to upgrade, but they unlock new workflows:
538
+
539
+ - **MCP server** — `bin/mcp-server.js` (also installed as `codeceptjs-mcp`) exposes CodeceptJS to AI agents through Model Context Protocol. See [MCP](/mcp).
540
+ - **WebElement wrapper** — `grabWebElements()` returns helper-agnostic `WebElement` instances with a unified API.
541
+ - **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).
542
+ - **Locator DSL** — `locate(...)` gains `.withClass()`, `.not()` negation, raw-predicate helpers, and a `role` selector type.
543
+ - **Workers** — the `event` dispatcher fires inside worker processes, so listeners and plugins observe parallel runs the same way they observe single-process runs.
544
+ - **Path normalization** — file-path handling is normalized cross-platform; tests authored on Windows run unchanged on Linux/CI.
545
+ - **Test metadata** — the `Scenario` callback receives a `test` object with `test.tags`, `test.artifacts`, `test.meta`, and `test.notes` for custom reporting.
546
+ - **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)).
547
+
548
+ ## 9. Verify the Upgrade
549
+
550
+ 1. `npx codeceptjs check` — surfaces config issues.
551
+ 2. `npx codeceptjs run --debug` on a small smoke suite. Confirm the run starts and steps execute.
552
+ 3. `npx codeceptjs run --workers 2` — confirm parallel execution.
553
+ 4. TypeScript users: run with `tsx` installed and confirm error stack traces point at `.ts` files.
554
+ 5. If you removed `autoLogin`: confirm sessions restore under the `auth` plugin.
555
+ 6. If you used `tryTo` / `retryTo` / `eachElement` plugins: grep your tests for the old globals and switch to subpath imports.
556
+ 7. CI: bump the Node version to 20+ if you were on 18 or below.