codeceptjs 4.0.0-rc.8 → 4.0.0

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