codeceptjs 4.0.0-rc.17 → 4.0.0-rc.19

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 (240) hide show
  1. package/bin/codecept.js +15 -2
  2. package/bin/codeceptq.js +49 -0
  3. package/bin/mcp-server.js +733 -196
  4. package/docs/advanced.md +201 -0
  5. package/docs/agents.md +159 -0
  6. package/docs/ai.md +537 -0
  7. package/docs/aitrace.md +266 -0
  8. package/docs/api.md +332 -0
  9. package/docs/assertions.md +415 -0
  10. package/docs/auth.md +318 -0
  11. package/docs/basics.md +424 -0
  12. package/docs/bdd.md +539 -0
  13. package/docs/best.md +240 -0
  14. package/docs/bootstrap.md +132 -0
  15. package/docs/commands.md +352 -0
  16. package/docs/community-helpers.md +63 -0
  17. package/docs/configuration.md +230 -0
  18. package/docs/continuous-integration.md +497 -0
  19. package/docs/custom-helpers.md +297 -0
  20. package/docs/data.md +448 -0
  21. package/docs/debugging.md +332 -0
  22. package/docs/detox.md +235 -0
  23. package/docs/docker.md +136 -0
  24. package/docs/effects.md +179 -0
  25. package/docs/element-based-testing.md +295 -0
  26. package/docs/element-selection.md +125 -0
  27. package/docs/els.md +328 -0
  28. package/docs/examples.md +161 -0
  29. package/docs/heal.md +213 -0
  30. package/docs/helpers/ApiDataFactory.md +267 -0
  31. package/docs/helpers/Appium.md +1405 -0
  32. package/docs/helpers/Detox.md +665 -0
  33. package/docs/helpers/ExpectHelper.md +275 -0
  34. package/docs/helpers/FileSystem.md +152 -0
  35. package/docs/helpers/GraphQL.md +152 -0
  36. package/docs/helpers/GraphQLDataFactory.md +226 -0
  37. package/docs/helpers/JSONResponse.md +255 -0
  38. package/docs/helpers/Mochawesome.md +8 -0
  39. package/docs/helpers/MockRequest.md +377 -0
  40. package/docs/helpers/MockServer.md +212 -0
  41. package/docs/helpers/Playwright.md +2969 -0
  42. package/docs/helpers/Polly.md +44 -0
  43. package/docs/helpers/Protractor.md +1769 -0
  44. package/docs/helpers/Puppeteer-firefox.md +86 -0
  45. package/docs/helpers/Puppeteer.md +2690 -0
  46. package/docs/helpers/REST.md +289 -0
  47. package/docs/helpers/SoftExpectHelper.md +352 -0
  48. package/docs/helpers/WebDriver.md +2682 -0
  49. package/docs/hooks.md +339 -0
  50. package/docs/index.md +111 -0
  51. package/docs/installation.md +83 -0
  52. package/docs/internal-api.md +265 -0
  53. package/docs/internal-test-server.md +89 -0
  54. package/docs/locators.md +355 -0
  55. package/docs/mcp.md +485 -0
  56. package/docs/migration-4.md +556 -0
  57. package/docs/mobile.md +338 -0
  58. package/docs/pageobjects.md +399 -0
  59. package/docs/parallel.md +585 -0
  60. package/docs/playwright.md +714 -0
  61. package/docs/plugins.md +866 -0
  62. package/docs/puppeteer.md +314 -0
  63. package/docs/quickstart.md +120 -0
  64. package/docs/react.md +70 -0
  65. package/docs/reports.md +483 -0
  66. package/docs/retry.md +274 -0
  67. package/docs/secrets.md +150 -0
  68. package/docs/sessions.md +80 -0
  69. package/docs/shadow.md +68 -0
  70. package/docs/test-structure.md +275 -0
  71. package/docs/timeouts.md +183 -0
  72. package/docs/translation.md +247 -0
  73. package/docs/tutorial.md +271 -0
  74. package/docs/typescript.md +374 -0
  75. package/docs/web-element.md +251 -0
  76. package/docs/webdriver.md +708 -0
  77. package/docs/within.md +55 -0
  78. package/lib/aria.js +260 -0
  79. package/lib/command/dryRun.js +23 -3
  80. package/lib/command/init.js +247 -266
  81. package/lib/command/list.js +150 -10
  82. package/lib/command/query.js +218 -0
  83. package/lib/config.js +77 -4
  84. package/lib/container.js +34 -2
  85. package/lib/element/WebElement.js +37 -0
  86. package/lib/globals.js +11 -10
  87. package/lib/helper/Playwright.js +5 -6
  88. package/lib/helper/extras/PlaywrightReactVueLocator.js +45 -36
  89. package/lib/html.js +90 -16
  90. package/lib/index.js +9 -1
  91. package/lib/locator.js +2 -2
  92. package/lib/mocha/factory.js +5 -1
  93. package/lib/mocha/inject.js +1 -1
  94. package/lib/parser.js +2 -2
  95. package/lib/pause.js +38 -4
  96. package/lib/plugin/aiTrace.js +72 -84
  97. package/lib/plugin/browser.js +77 -0
  98. package/lib/plugin/expose.js +159 -0
  99. package/lib/plugin/heal.js +44 -1
  100. package/lib/plugin/pageInfo.js +51 -48
  101. package/lib/plugin/pause.js +131 -0
  102. package/lib/plugin/pauseOnFail.js +10 -34
  103. package/lib/plugin/screencast.js +287 -0
  104. package/lib/plugin/screenshot.js +563 -0
  105. package/lib/plugin/screenshotOnFail.js +8 -170
  106. package/lib/utils/pluginParser.js +151 -0
  107. package/lib/utils/trace.js +297 -0
  108. package/lib/utils.js +25 -0
  109. package/lib/workers.js +1 -15
  110. package/package.json +12 -10
  111. package/typings/index.d.ts +0 -5
  112. package/docs/webapi/amOnPage.mustache +0 -11
  113. package/docs/webapi/appendField.mustache +0 -16
  114. package/docs/webapi/attachFile.mustache +0 -24
  115. package/docs/webapi/blur.mustache +0 -18
  116. package/docs/webapi/checkOption.mustache +0 -13
  117. package/docs/webapi/clearCookie.mustache +0 -9
  118. package/docs/webapi/clearField.mustache +0 -14
  119. package/docs/webapi/click.mustache +0 -29
  120. package/docs/webapi/clickLink.mustache +0 -8
  121. package/docs/webapi/closeCurrentTab.mustache +0 -7
  122. package/docs/webapi/closeOtherTabs.mustache +0 -8
  123. package/docs/webapi/dontSee.mustache +0 -11
  124. package/docs/webapi/dontSeeCheckboxIsChecked.mustache +0 -10
  125. package/docs/webapi/dontSeeCookie.mustache +0 -8
  126. package/docs/webapi/dontSeeCurrentPathEquals.mustache +0 -10
  127. package/docs/webapi/dontSeeCurrentUrlEquals.mustache +0 -10
  128. package/docs/webapi/dontSeeElement.mustache +0 -12
  129. package/docs/webapi/dontSeeElementInDOM.mustache +0 -8
  130. package/docs/webapi/dontSeeInCurrentUrl.mustache +0 -4
  131. package/docs/webapi/dontSeeInField.mustache +0 -16
  132. package/docs/webapi/dontSeeInSource.mustache +0 -8
  133. package/docs/webapi/dontSeeInTitle.mustache +0 -8
  134. package/docs/webapi/dontSeeTraffic.mustache +0 -13
  135. package/docs/webapi/doubleClick.mustache +0 -13
  136. package/docs/webapi/downloadFile.mustache +0 -12
  137. package/docs/webapi/dragAndDrop.mustache +0 -9
  138. package/docs/webapi/dragSlider.mustache +0 -11
  139. package/docs/webapi/executeAsyncScript.mustache +0 -24
  140. package/docs/webapi/executeScript.mustache +0 -26
  141. package/docs/webapi/fillField.mustache +0 -21
  142. package/docs/webapi/flushNetworkTraffics.mustache +0 -5
  143. package/docs/webapi/focus.mustache +0 -13
  144. package/docs/webapi/forceClick.mustache +0 -28
  145. package/docs/webapi/forceRightClick.mustache +0 -18
  146. package/docs/webapi/grabAllWindowHandles.mustache +0 -7
  147. package/docs/webapi/grabAttributeFrom.mustache +0 -10
  148. package/docs/webapi/grabAttributeFromAll.mustache +0 -9
  149. package/docs/webapi/grabBrowserLogs.mustache +0 -9
  150. package/docs/webapi/grabCookie.mustache +0 -11
  151. package/docs/webapi/grabCssPropertyFrom.mustache +0 -11
  152. package/docs/webapi/grabCssPropertyFromAll.mustache +0 -10
  153. package/docs/webapi/grabCurrentUrl.mustache +0 -9
  154. package/docs/webapi/grabCurrentWindowHandle.mustache +0 -6
  155. package/docs/webapi/grabDataFromPerformanceTiming.mustache +0 -20
  156. package/docs/webapi/grabElementBoundingRect.mustache +0 -20
  157. package/docs/webapi/grabGeoLocation.mustache +0 -8
  158. package/docs/webapi/grabHTMLFrom.mustache +0 -10
  159. package/docs/webapi/grabHTMLFromAll.mustache +0 -9
  160. package/docs/webapi/grabNumberOfOpenTabs.mustache +0 -8
  161. package/docs/webapi/grabNumberOfVisibleElements.mustache +0 -9
  162. package/docs/webapi/grabPageScrollPosition.mustache +0 -8
  163. package/docs/webapi/grabPopupText.mustache +0 -5
  164. package/docs/webapi/grabRecordedNetworkTraffics.mustache +0 -10
  165. package/docs/webapi/grabSource.mustache +0 -8
  166. package/docs/webapi/grabTextFrom.mustache +0 -10
  167. package/docs/webapi/grabTextFromAll.mustache +0 -9
  168. package/docs/webapi/grabTitle.mustache +0 -8
  169. package/docs/webapi/grabValueFrom.mustache +0 -9
  170. package/docs/webapi/grabValueFromAll.mustache +0 -8
  171. package/docs/webapi/grabWebElement.mustache +0 -9
  172. package/docs/webapi/grabWebElements.mustache +0 -9
  173. package/docs/webapi/moveCursorTo.mustache +0 -16
  174. package/docs/webapi/openNewTab.mustache +0 -7
  175. package/docs/webapi/pressKey.mustache +0 -12
  176. package/docs/webapi/pressKeyDown.mustache +0 -12
  177. package/docs/webapi/pressKeyUp.mustache +0 -12
  178. package/docs/webapi/pressKeyWithKeyNormalization.mustache +0 -60
  179. package/docs/webapi/refreshPage.mustache +0 -6
  180. package/docs/webapi/resizeWindow.mustache +0 -6
  181. package/docs/webapi/rightClick.mustache +0 -14
  182. package/docs/webapi/saveElementScreenshot.mustache +0 -10
  183. package/docs/webapi/saveScreenshot.mustache +0 -12
  184. package/docs/webapi/say.mustache +0 -10
  185. package/docs/webapi/scrollIntoView.mustache +0 -11
  186. package/docs/webapi/scrollPageToBottom.mustache +0 -6
  187. package/docs/webapi/scrollPageToTop.mustache +0 -6
  188. package/docs/webapi/scrollTo.mustache +0 -12
  189. package/docs/webapi/see.mustache +0 -11
  190. package/docs/webapi/seeAttributesOnElements.mustache +0 -9
  191. package/docs/webapi/seeCheckboxIsChecked.mustache +0 -10
  192. package/docs/webapi/seeCookie.mustache +0 -8
  193. package/docs/webapi/seeCssPropertiesOnElements.mustache +0 -9
  194. package/docs/webapi/seeCurrentPathEquals.mustache +0 -10
  195. package/docs/webapi/seeCurrentUrlEquals.mustache +0 -11
  196. package/docs/webapi/seeElement.mustache +0 -12
  197. package/docs/webapi/seeElementInDOM.mustache +0 -8
  198. package/docs/webapi/seeInCurrentUrl.mustache +0 -8
  199. package/docs/webapi/seeInField.mustache +0 -17
  200. package/docs/webapi/seeInPopup.mustache +0 -8
  201. package/docs/webapi/seeInSource.mustache +0 -7
  202. package/docs/webapi/seeInTitle.mustache +0 -8
  203. package/docs/webapi/seeNumberOfElements.mustache +0 -11
  204. package/docs/webapi/seeNumberOfVisibleElements.mustache +0 -10
  205. package/docs/webapi/seeTextEquals.mustache +0 -9
  206. package/docs/webapi/seeTitleEquals.mustache +0 -8
  207. package/docs/webapi/seeTraffic.mustache +0 -36
  208. package/docs/webapi/selectOption.mustache +0 -26
  209. package/docs/webapi/setCookie.mustache +0 -16
  210. package/docs/webapi/setGeoLocation.mustache +0 -12
  211. package/docs/webapi/startRecordingTraffic.mustache +0 -8
  212. package/docs/webapi/startRecordingWebSocketMessages.mustache +0 -8
  213. package/docs/webapi/stopRecordingTraffic.mustache +0 -5
  214. package/docs/webapi/stopRecordingWebSocketMessages.mustache +0 -7
  215. package/docs/webapi/switchTo.mustache +0 -9
  216. package/docs/webapi/switchToNextTab.mustache +0 -10
  217. package/docs/webapi/switchToPreviousTab.mustache +0 -10
  218. package/docs/webapi/type.mustache +0 -21
  219. package/docs/webapi/uncheckOption.mustache +0 -13
  220. package/docs/webapi/wait.mustache +0 -8
  221. package/docs/webapi/waitForClickable.mustache +0 -11
  222. package/docs/webapi/waitForCookie.mustache +0 -9
  223. package/docs/webapi/waitForDetached.mustache +0 -10
  224. package/docs/webapi/waitForDisabled.mustache +0 -6
  225. package/docs/webapi/waitForElement.mustache +0 -11
  226. package/docs/webapi/waitForEnabled.mustache +0 -6
  227. package/docs/webapi/waitForFunction.mustache +0 -17
  228. package/docs/webapi/waitForInvisible.mustache +0 -10
  229. package/docs/webapi/waitForNumberOfTabs.mustache +0 -9
  230. package/docs/webapi/waitForText.mustache +0 -13
  231. package/docs/webapi/waitForValue.mustache +0 -10
  232. package/docs/webapi/waitForVisible.mustache +0 -10
  233. package/docs/webapi/waitInUrl.mustache +0 -9
  234. package/docs/webapi/waitNumberOfVisibleElements.mustache +0 -10
  235. package/docs/webapi/waitToHide.mustache +0 -10
  236. package/docs/webapi/waitUrlEquals.mustache +0 -10
  237. package/lib/helper/AI.js +0 -214
  238. package/lib/plugin/pauseOn.js +0 -167
  239. package/lib/plugin/stepByStepReport.js +0 -432
  240. package/lib/plugin/subtitles.js +0 -89
package/docs/retry.md ADDED
@@ -0,0 +1,274 @@
1
+ ---
2
+ permalink: /retry
3
+ title: Retry Mechanisms
4
+ ---
5
+
6
+ # Retry Mechanisms
7
+
8
+ CodeceptJS provides flexible retry mechanisms to handle flaky tests. Use retries when dealing with unstable environments, network delays, or timing issues — not to mask bugs in your code.
9
+
10
+ ## Helper Retries
11
+
12
+ Browser automation helpers (Playwright, Puppeteer, WebDriver) have **built-in retry mechanisms** for element interactions. When you call `I.click('Button')`, Playwright automatically waits for the element to exist, be visible, stable, and enabled — retrying for up to 5 seconds.
13
+
14
+ Configure the timeout in your helper settings:
15
+
16
+ ```js
17
+ helpers: {
18
+ Playwright: {
19
+ timeout: 5000, // retry actions for up to 5 seconds
20
+ waitForAction: 100 // wait 100ms before each action
21
+ }
22
+ }
23
+ ```
24
+
25
+ **Learn more:** [Playwright Helper](/helpers/Playwright), [Timeouts](/timeouts)
26
+
27
+ ## CodeceptJS Retry Levels
28
+
29
+ When helper retries aren't enough, CodeceptJS adds retry layers on top.
30
+
31
+ ### 1. Manual Step Retry
32
+
33
+ Retry a specific step known to be flaky:
34
+
35
+ ```js
36
+ import step from 'codeceptjs/steps'
37
+
38
+ Scenario('checkout', ({ I }) => {
39
+ I.amOnPage('/cart')
40
+ I.click('Proceed to Checkout', step.retry(5)) // retry up to 5 times
41
+ I.see('Payment')
42
+ })
43
+ ```
44
+
45
+ Configure timing with exponential backoff:
46
+
47
+ ```js
48
+ I.click('Submit', step.retry({
49
+ retries: 3,
50
+ minTimeout: 1000, // wait 1 second before first retry
51
+ maxTimeout: 5000, // max 5 seconds between retries
52
+ factor: 1.5 // exponential backoff multiplier
53
+ }))
54
+ ```
55
+
56
+ Pass `0` for infinite retries.
57
+
58
+ ### 2. Automatic Step Retry
59
+
60
+ Automatically retry all failed steps without modifying test code:
61
+
62
+ ```js
63
+ plugins: {
64
+ retryFailedStep: {
65
+ enabled: true,
66
+ retries: 3
67
+ }
68
+ }
69
+ ```
70
+
71
+ Steps matching `amOnPage`, `wait*`, `send*`, `execute*`, `run*`, `have*` are skipped by default.
72
+
73
+ When a scenario has its own retries, step retries are disabled by default (`deferToScenarioRetries: true`). This prevents excessive execution time:
74
+
75
+ ```js
76
+ Scenario('test', { retries: 2 }, ({ I }) => {
77
+ I.click('Button') // step retries disabled; scenario retries run instead
78
+ })
79
+ ```
80
+
81
+ To disable step retries for a specific test:
82
+
83
+ ```js
84
+ Scenario('manual retries only', { disableRetryFailedStep: true }, ({ I }) => {
85
+ I.click('Button', step.retry(5))
86
+ })
87
+ ```
88
+
89
+ Full plugin options:
90
+
91
+ | Option | Default | Description |
92
+ |--------|---------|-------------|
93
+ | `retries` | — | Retries per step |
94
+ | `minTimeout` | — | Milliseconds before first retry |
95
+ | `maxTimeout` | `Infinity` | Max milliseconds between retries |
96
+ | `factor` | — | Exponential backoff multiplier |
97
+ | `randomize` | `false` | Randomize timeout intervals |
98
+ | `ignoredSteps` | `[]` | Patterns/regex of steps to never retry |
99
+ | `deferToScenarioRetries` | `true` | Disable step retries when scenario retries exist |
100
+ | `when` | `() => true` | Function receiving error; return `true` to retry |
101
+
102
+ ### 3. Multiple Steps Retry (retryTo)
103
+
104
+ Retry a group of steps together as a single operation:
105
+
106
+ ```js
107
+ import { retryTo } from 'codeceptjs/effects'
108
+
109
+ await retryTo(() => {
110
+ I.click('Load More')
111
+ I.see('New Content')
112
+ }, 3)
113
+ ```
114
+
115
+ If any step inside fails, the entire block retries. Use this for sequences that must succeed together — switching into an iframe and filling a form, for example.
116
+
117
+ **Learn more:** [Effects](/effects#retryto)
118
+
119
+ ### 4. Self-Healing Steps
120
+
121
+ When a step fails, a healing recipe runs recovery actions and continues the test — without touching test code. With AI healing enabled:
122
+
123
+ ```js
124
+ Scenario('checkout', ({ I }) => {
125
+ I.click('Proceed to Checkout')
126
+ I.see('Payment')
127
+ })
128
+ ```
129
+
130
+ - `I.click('Proceed to Checkout')` fails — button was renamed or moved
131
+ - failed step, error message, and page HTML are sent to an LLM
132
+ - AI scans page elements and suggests valid replacement actions
133
+ - CodeceptJS executes the suggestions until one succeeds
134
+ - test continues with `I.see('Payment')`
135
+
136
+ Run with `--ai` to activate:
137
+
138
+ ```bash
139
+ npx codeceptjs run --ai
140
+ ```
141
+
142
+ You can also write custom recipes for non-UI failures — network errors, data glitches, UI migrations.
143
+
144
+ **Learn more:** [Self-Healing Tests](/heal), [AI Configuration](/ai)
145
+
146
+ ### 5. Scenario Retry
147
+
148
+ Retry an entire test when it fails:
149
+
150
+ ```js
151
+ Scenario('API integration', { retries: 3 }, ({ I }) => {
152
+ I.sendGetRequest('/api/users')
153
+ I.seeResponseCodeIs(200)
154
+ })
155
+ ```
156
+
157
+ Retry all scenarios globally, or by grep pattern:
158
+
159
+ ```js
160
+ export const config = {
161
+ retry: [
162
+ { Scenario: 3, grep: 'API' }, // retry scenarios containing "API" 3 times
163
+ { Scenario: 5, grep: '@flaky' } // retry @flaky-tagged scenarios 5 times
164
+ ]
165
+ }
166
+ ```
167
+
168
+ ### 6. Feature Retry
169
+
170
+ Retry all scenarios within a feature:
171
+
172
+ ```js
173
+ Feature('Payment Processing', { retries: 2 })
174
+
175
+ Scenario('credit card payment', ({ I }) => { ... }) // retries 2 times
176
+ Scenario('paypal payment', ({ I }) => { ... }) // retries 2 times
177
+ ```
178
+
179
+ Or target features by pattern in config:
180
+
181
+ ```js
182
+ export const config = {
183
+ retry: [
184
+ { Feature: 3, grep: 'Integration' }
185
+ ]
186
+ }
187
+ ```
188
+
189
+ ### 7. Hook Retries
190
+
191
+ Retry `Before`/`After` hooks when they fail:
192
+
193
+ ```js
194
+ Before(({ I }) => {
195
+ I.amOnPage('/')
196
+ }).retry(2)
197
+ ```
198
+
199
+ Set per feature:
200
+
201
+ ```js
202
+ Feature('My Suite', {
203
+ retryBefore: 2,
204
+ retryAfter: 1,
205
+ retryBeforeSuite: 3,
206
+ retryAfterSuite: 1
207
+ })
208
+ ```
209
+
210
+ Or globally:
211
+
212
+ ```js
213
+ export const config = {
214
+ retry: [
215
+ { BeforeSuite: 2, Before: 1, After: 1 }
216
+ ]
217
+ }
218
+ ```
219
+
220
+ ## Retry Priority
221
+
222
+ When multiple retry configurations exist, higher-priority retries take precedence:
223
+
224
+ | Priority | Type | Description |
225
+ |----------|------|-------------|
226
+ | **Highest** | Manual Step (`step.retry()`) | Explicit retries in test code |
227
+ | | Automatic Step | `retryFailedStep` plugin |
228
+ | | Multiple Steps (`retryTo`) | Retry groups of steps together |
229
+ | | Scenario Config | Retry entire scenarios |
230
+ | | Feature Config | Retry all scenarios in a feature |
231
+ | **Lowest** | Hook Config | Retry failed hooks |
232
+
233
+ `retryTo` operates independently from step-level retries. If a step inside `retryTo` fails, the entire block retries.
234
+
235
+ ## Best Practices
236
+
237
+ 1. **Understand helper retries first** — Playwright/Puppeteer/WebDriver already retry actions internally
238
+ 2. **Start with scenario retries** — simpler and less likely to cause issues
239
+ 3. **Use manual retries for known flaky steps** — most predictable behavior
240
+ 4. **Enable `deferToScenarioRetries`** — prevents excessive retries (default)
241
+ 5. **Don't over-retry** — if tests fail consistently, fix the root cause
242
+ 6. **Use grep patterns** — apply retries only where needed
243
+ 7. **Retry timeouts, not bugs** — retries handle environmental issues, not code defects
244
+ 8. **Consider healing for complex recovery** — see [Self-Healing Tests](/heal)
245
+
246
+ ## Troubleshooting
247
+
248
+ ### Tests running too long
249
+
250
+ - Confirm `deferToScenarioRetries: true` (the default)
251
+ - Reduce retry counts
252
+ - Use `grep` patterns to target specific tests
253
+ - Add problematic steps to `ignoredSteps`
254
+
255
+ ### Retries not working
256
+
257
+ 1. Check configuration syntax
258
+ 2. Check the priority table — a higher-priority retry may be overriding
259
+ 3. Confirm `disableRetryFailedStep: true` is not set on the scenario
260
+ 4. Confirm the step isn't in `ignoredSteps`
261
+
262
+ Debug with:
263
+
264
+ ```bash
265
+ DEBUG_RETRY_PLUGIN=1 npx codeceptjs run
266
+ ```
267
+
268
+ ### `step.retry()` is undefined
269
+
270
+ Import `step` from codeceptjs:
271
+
272
+ ```js
273
+ import step from 'codeceptjs/steps'
274
+ ```
@@ -0,0 +1,150 @@
1
+ # Secrets
2
+
3
+ It is possible to **mask out sensitive data** when passing it to steps. This is important when filling password fields, or sending secure keys to API endpoint. CodeceptJS provides two approaches for masking sensitive data:
4
+
5
+ ## 1. Using the `secret()` Function
6
+
7
+ Wrap data in `secret` function to mask sensitive values in output and logs.
8
+
9
+ For basic string `secret` just wrap a value into a string:
10
+
11
+ ```js
12
+ I.fillField('password', secret('123456'))
13
+ ```
14
+
15
+ When executed it will be printed like this:
16
+
17
+ ```
18
+ I fill field "password" "*****"
19
+ ```
20
+
21
+ **Other Examples**
22
+
23
+ ```js
24
+ I.fillField('password', secret('123456'))
25
+ I.append('password', secret('123456'))
26
+ I.type('password', secret('123456'))
27
+ ```
28
+
29
+ For an object, which can be a payload to POST request, specify which fields should be masked:
30
+
31
+ ```js
32
+ I.sendPostRequest(
33
+ '/login',
34
+ secret(
35
+ {
36
+ name: 'davert',
37
+ password: '123456',
38
+ },
39
+ 'password',
40
+ ),
41
+ )
42
+ ```
43
+
44
+ The object created from `secret` is as Proxy to the object passed in. When printed password will be replaced with \*\*\*\*.
45
+
46
+ > ⚠️ Only direct properties of the object can be masked via `secret`
47
+
48
+ ## 2. Global Sensitive Data Masking
49
+
50
+ CodeceptJS can automatically mask sensitive data in all output (logs, steps, debug messages, errors) using configurable patterns. This feature uses the `maskSensitiveData` configuration option.
51
+
52
+ ### Basic Usage (Boolean)
53
+
54
+ Enable basic masking with predefined patterns:
55
+
56
+ ```js
57
+ // codecept.conf.js
58
+ export const config = {
59
+ // ... other config
60
+ maskSensitiveData: true,
61
+ }
62
+ ```
63
+
64
+ This will mask common sensitive data patterns like:
65
+
66
+ - Authorization headers
67
+ - API keys
68
+ - Passwords
69
+ - Tokens
70
+ - Client secrets
71
+
72
+ ### Advanced Usage (Custom Patterns)
73
+
74
+ Define your own masking patterns:
75
+
76
+ ```js
77
+ // codecept.conf.js
78
+ export const config = {
79
+ // ... other config
80
+ maskSensitiveData: {
81
+ enabled: true,
82
+ patterns: [
83
+ {
84
+ name: 'Email',
85
+ regex: /(\b[A-Za-z0-9._%+-]+@[A-Za-z0-9.-]+\.[A-Z|a-z]{2,}\b)/gi,
86
+ mask: '[MASKED_EMAIL]',
87
+ },
88
+ {
89
+ name: 'Credit Card',
90
+ regex: /\b(?:\d{4}[- ]?){3}\d{4}\b/g,
91
+ mask: '[MASKED_CARD]',
92
+ },
93
+ {
94
+ name: 'Phone Number',
95
+ regex: /(\+?1[-.\s]?)?\(?([0-9]{3})\)?[-.\s]?([0-9]{3})[-.\s]?([0-9]{4})/g,
96
+ mask: '[MASKED_PHONE]',
97
+ },
98
+ {
99
+ name: 'SSN',
100
+ regex: /\b\d{3}-\d{2}-\d{4}\b/g,
101
+ mask: '[MASKED_SSN]',
102
+ },
103
+ ],
104
+ },
105
+ }
106
+ ```
107
+
108
+ ### Pattern Configuration
109
+
110
+ Each custom pattern object should have:
111
+
112
+ - `name`: A descriptive name for the pattern
113
+ - `regex`: A JavaScript regular expression to match the sensitive data
114
+ - `mask`: The replacement string to show instead of the sensitive data
115
+
116
+ ### Examples
117
+
118
+ With the above configuration:
119
+
120
+ **Input:**
121
+
122
+ ```
123
+ User email: john.doe@company.com
124
+ Credit card: 4111 1111 1111 1111
125
+ Phone: +1-555-123-4567
126
+ ```
127
+
128
+ **Output:**
129
+
130
+ ```
131
+ User email: [MASKED_EMAIL]
132
+ Credit card: [MASKED_CARD]
133
+ Phone: [MASKED_PHONE]
134
+ ```
135
+
136
+ ### Where Masking Applies
137
+
138
+ Global sensitive data masking is applied to:
139
+
140
+ - Step descriptions and output
141
+ - Debug messages (`--debug` mode)
142
+ - Log messages (`--verbose` mode)
143
+ - Error messages
144
+ - Success messages
145
+
146
+ > ⚠️ Direct `console.log()` calls in helper functions are not masked. Use CodeceptJS output functions instead.
147
+
148
+ ### Combining Both Approaches
149
+
150
+ You can use both `secret()` function and global masking together. The `secret()` function is applied first, then global patterns are applied to the remaining output.
@@ -0,0 +1,80 @@
1
+ ---
2
+ permalink: /sessions
3
+ title: Multiple Sessions
4
+ ---
5
+
6
+ # Multiple Sessions
7
+
8
+ CodeceptJS can run several browser sessions in a single test. This is useful for testing real-time features like chat, notifications, or multi-user workflows.
9
+
10
+ ```js
11
+ Scenario('two users chat', ({ I }) => {
12
+ I.amOnPage('/chat')
13
+ I.fillField('name', 'davert')
14
+ I.click('Sign In')
15
+ I.see('Hello, davert')
16
+
17
+ session('john', () => {
18
+ I.amOnPage('/chat')
19
+ I.fillField('name', 'john')
20
+ I.click('Sign In')
21
+ I.see('Hello, john')
22
+ })
23
+
24
+ // back in default session (davert)
25
+ I.fillField('message', 'Hi, john')
26
+ I.see('me: Hi, john', '.messages')
27
+
28
+ session('john', () => {
29
+ I.see('davert: Hi, john', '.messages')
30
+ })
31
+ })
32
+ ```
33
+
34
+ Switch back to a session at any point by using the same name.
35
+
36
+ ## Session Configuration
37
+
38
+ Override the browser config for a specific session:
39
+
40
+ ```js
41
+ session('mobile', { browser: 'webkit', viewport: { width: 375, height: 812 } }, () => {
42
+ I.amOnPage('/')
43
+ I.see('Mobile View')
44
+ })
45
+ ```
46
+
47
+ ## Opening Sessions Without Switching
48
+
49
+ Open sessions in the background without switching to them immediately:
50
+
51
+ ```js
52
+ Scenario('multi-user test', ({ I }) => {
53
+ session('john')
54
+ session('mary')
55
+ session('jane')
56
+
57
+ I.amOnPage('/')
58
+
59
+ session('mary', () => {
60
+ I.amOnPage('/login')
61
+ })
62
+ })
63
+ ```
64
+
65
+ ## Returning Values
66
+
67
+ `session` can return a value for use in the main scenario:
68
+
69
+ ```js
70
+ const profileName = await session('john', () => {
71
+ I.amOnPage('/profile')
72
+ return I.grabTextFrom({ css: 'h1' })
73
+ })
74
+ I.fillField('Recipient', profileName)
75
+ ```
76
+
77
+ ## Notes
78
+
79
+ - Sessions can use the `I` object, page objects, and any other objects declared for the scenario
80
+ - `within` can be used inside a session, but `session` cannot be called from inside `within`
package/docs/shadow.md ADDED
@@ -0,0 +1,68 @@
1
+ ---
2
+ permalink: /shadow
3
+ title: Locating Shadow Dom Elements
4
+ ---
5
+
6
+ # Locating Shadow Dom Elements
7
+
8
+ > ℹ Shadow DOM locators is supported only in WebDriver helper
9
+
10
+ Shadow DOM is one of the key browser features that make up web components. Web components are a really great way to build reusable elements, and are able to scale all the way up to complete web applications. Style encapsulation, the feature that gives shadow DOM it's power, has been a bit of a pain when it comes to E2E or UI testing. Things just got a little easier though, as CodeceptJS introduced built-in support for shadow DOM via locators of type `shadow`. Let's dig into what they're all about.
11
+
12
+ Generated HTML code may often look like this (ref: [Salesforce's Lighting Web Components](https://github.com/salesforce/lwc)):
13
+
14
+ ```js
15
+ <body>
16
+ <my-app>
17
+ <recipe-hello>
18
+ <button>Click Me!</button>
19
+ </recipe-hello>
20
+ <recipe-hello-binding>
21
+ <ui-input>
22
+ <input type="text" class="input">
23
+ </ui-input>
24
+ </recipe-hello-binding>
25
+ </my-app>
26
+ </body>
27
+ ```
28
+
29
+ This uses custom elements, `my-app`, `recipe-hello`, `recipe-hello-binding` and `ui-input`. It's quite common that clickable elements are not actual `a` or `button` elements but custom elements. This way `I.click('Click Me!');` won't work, as well as `fillField('.input', 'value)`. Finding a correct locator for such cases turns to be almost impossible until `shadow` element support is added to CodeceptJS.
30
+
31
+ ## Locate Shadow Dom
32
+
33
+ For Web Components or [Salesforce's Lighting Web Components](https://github.com/salesforce/lwc) with Shadow DOM's, a special `shadow` locator is available. It allows to select an element by its shadow dom sequences and sequences are defined as an Array of `elements`. Elements defined in the array of `elements` must be in the ordered the shadow elements appear in the DOM.
34
+
35
+ ```js
36
+ { shadow: ['my-app', 'recipe-hello', 'button'] }
37
+ { shadow: ['my-app', 'recipe-hello-binding', 'ui-input', 'input.input'] }
38
+ ```
39
+
40
+ In WebDriver, you can use shadow locators in any method where locator is required.
41
+
42
+ For example, to fill value in `input` field or to click the `Click Me!` button, in above HTML code:
43
+
44
+ ```js
45
+ I.fillField({ shadow: ['my-app', 'recipe-hello-binding', 'ui-input', 'input.input'] }, 'value');
46
+ I.click({ shadow: ['my-app', 'recipe-hello', 'button'] });
47
+ ```
48
+
49
+ ## Example
50
+
51
+ ```js
52
+ Feature('Shadow Dom Locators');
53
+
54
+ Scenario('should fill input field within shadow elements', ({I}) => {
55
+
56
+ // navigate to LWC webpage containing shadow dom
57
+ I.amOnPage('https://recipes.lwc.dev/');
58
+
59
+ // click Click Me! button
60
+ I.click({ shadow: ['my-app', 'recipe-hello', 'button'] });
61
+
62
+ // fill the input field
63
+ I.fillField({ shadow: ['my-app', 'recipe-hello-binding', 'ui-input', 'input.input'] }, 'value');
64
+
65
+ });
66
+
67
+
68
+ ```