codeceptjs 4.0.0-rc.18 → 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 (220) hide show
  1. package/bin/codecept.js +5 -1
  2. package/bin/codeceptq.js +49 -0
  3. package/bin/mcp-server.js +250 -82
  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/command/dryRun.js +9 -3
  79. package/lib/command/init.js +247 -266
  80. package/lib/command/query.js +218 -0
  81. package/lib/config.js +9 -0
  82. package/lib/element/WebElement.js +37 -0
  83. package/lib/globals.js +11 -10
  84. package/lib/helper/Playwright.js +4 -1
  85. package/lib/html.js +3 -0
  86. package/lib/index.js +9 -1
  87. package/lib/locator.js +2 -2
  88. package/lib/mocha/factory.js +5 -1
  89. package/lib/mocha/inject.js +1 -1
  90. package/lib/parser.js +2 -2
  91. package/lib/plugin/browser.js +2 -1
  92. package/lib/plugin/expose.js +159 -0
  93. package/lib/workers.js +1 -15
  94. package/package.json +7 -5
  95. package/docs/webapi/amOnPage.mustache +0 -11
  96. package/docs/webapi/appendField.mustache +0 -16
  97. package/docs/webapi/attachFile.mustache +0 -24
  98. package/docs/webapi/blur.mustache +0 -18
  99. package/docs/webapi/checkOption.mustache +0 -13
  100. package/docs/webapi/clearCookie.mustache +0 -9
  101. package/docs/webapi/clearField.mustache +0 -14
  102. package/docs/webapi/click.mustache +0 -29
  103. package/docs/webapi/clickLink.mustache +0 -8
  104. package/docs/webapi/closeCurrentTab.mustache +0 -7
  105. package/docs/webapi/closeOtherTabs.mustache +0 -8
  106. package/docs/webapi/dontSee.mustache +0 -11
  107. package/docs/webapi/dontSeeCheckboxIsChecked.mustache +0 -10
  108. package/docs/webapi/dontSeeCookie.mustache +0 -8
  109. package/docs/webapi/dontSeeCurrentPathEquals.mustache +0 -10
  110. package/docs/webapi/dontSeeCurrentUrlEquals.mustache +0 -10
  111. package/docs/webapi/dontSeeElement.mustache +0 -12
  112. package/docs/webapi/dontSeeElementInDOM.mustache +0 -8
  113. package/docs/webapi/dontSeeInCurrentUrl.mustache +0 -4
  114. package/docs/webapi/dontSeeInField.mustache +0 -16
  115. package/docs/webapi/dontSeeInSource.mustache +0 -8
  116. package/docs/webapi/dontSeeInTitle.mustache +0 -8
  117. package/docs/webapi/dontSeeTraffic.mustache +0 -13
  118. package/docs/webapi/doubleClick.mustache +0 -13
  119. package/docs/webapi/downloadFile.mustache +0 -12
  120. package/docs/webapi/dragAndDrop.mustache +0 -9
  121. package/docs/webapi/dragSlider.mustache +0 -11
  122. package/docs/webapi/executeAsyncScript.mustache +0 -24
  123. package/docs/webapi/executeScript.mustache +0 -26
  124. package/docs/webapi/fillField.mustache +0 -21
  125. package/docs/webapi/flushNetworkTraffics.mustache +0 -5
  126. package/docs/webapi/focus.mustache +0 -13
  127. package/docs/webapi/forceClick.mustache +0 -28
  128. package/docs/webapi/forceRightClick.mustache +0 -18
  129. package/docs/webapi/grabAllWindowHandles.mustache +0 -7
  130. package/docs/webapi/grabAttributeFrom.mustache +0 -10
  131. package/docs/webapi/grabAttributeFromAll.mustache +0 -9
  132. package/docs/webapi/grabBrowserLogs.mustache +0 -9
  133. package/docs/webapi/grabCookie.mustache +0 -11
  134. package/docs/webapi/grabCssPropertyFrom.mustache +0 -11
  135. package/docs/webapi/grabCssPropertyFromAll.mustache +0 -10
  136. package/docs/webapi/grabCurrentUrl.mustache +0 -9
  137. package/docs/webapi/grabCurrentWindowHandle.mustache +0 -6
  138. package/docs/webapi/grabDataFromPerformanceTiming.mustache +0 -20
  139. package/docs/webapi/grabElementBoundingRect.mustache +0 -20
  140. package/docs/webapi/grabGeoLocation.mustache +0 -8
  141. package/docs/webapi/grabHTMLFrom.mustache +0 -10
  142. package/docs/webapi/grabHTMLFromAll.mustache +0 -9
  143. package/docs/webapi/grabNumberOfOpenTabs.mustache +0 -8
  144. package/docs/webapi/grabNumberOfVisibleElements.mustache +0 -9
  145. package/docs/webapi/grabPageScrollPosition.mustache +0 -8
  146. package/docs/webapi/grabPopupText.mustache +0 -5
  147. package/docs/webapi/grabRecordedNetworkTraffics.mustache +0 -10
  148. package/docs/webapi/grabSource.mustache +0 -8
  149. package/docs/webapi/grabTextFrom.mustache +0 -10
  150. package/docs/webapi/grabTextFromAll.mustache +0 -9
  151. package/docs/webapi/grabTitle.mustache +0 -8
  152. package/docs/webapi/grabValueFrom.mustache +0 -9
  153. package/docs/webapi/grabValueFromAll.mustache +0 -8
  154. package/docs/webapi/grabWebElement.mustache +0 -9
  155. package/docs/webapi/grabWebElements.mustache +0 -9
  156. package/docs/webapi/moveCursorTo.mustache +0 -16
  157. package/docs/webapi/openNewTab.mustache +0 -7
  158. package/docs/webapi/pressKey.mustache +0 -12
  159. package/docs/webapi/pressKeyDown.mustache +0 -12
  160. package/docs/webapi/pressKeyUp.mustache +0 -12
  161. package/docs/webapi/pressKeyWithKeyNormalization.mustache +0 -60
  162. package/docs/webapi/refreshPage.mustache +0 -6
  163. package/docs/webapi/resizeWindow.mustache +0 -6
  164. package/docs/webapi/rightClick.mustache +0 -14
  165. package/docs/webapi/saveElementScreenshot.mustache +0 -10
  166. package/docs/webapi/saveScreenshot.mustache +0 -12
  167. package/docs/webapi/say.mustache +0 -10
  168. package/docs/webapi/scrollIntoView.mustache +0 -11
  169. package/docs/webapi/scrollPageToBottom.mustache +0 -6
  170. package/docs/webapi/scrollPageToTop.mustache +0 -6
  171. package/docs/webapi/scrollTo.mustache +0 -12
  172. package/docs/webapi/see.mustache +0 -11
  173. package/docs/webapi/seeAttributesOnElements.mustache +0 -9
  174. package/docs/webapi/seeCheckboxIsChecked.mustache +0 -10
  175. package/docs/webapi/seeCookie.mustache +0 -8
  176. package/docs/webapi/seeCssPropertiesOnElements.mustache +0 -9
  177. package/docs/webapi/seeCurrentPathEquals.mustache +0 -10
  178. package/docs/webapi/seeCurrentUrlEquals.mustache +0 -11
  179. package/docs/webapi/seeElement.mustache +0 -12
  180. package/docs/webapi/seeElementInDOM.mustache +0 -8
  181. package/docs/webapi/seeFileDownloaded.mustache +0 -23
  182. package/docs/webapi/seeInCurrentUrl.mustache +0 -8
  183. package/docs/webapi/seeInField.mustache +0 -17
  184. package/docs/webapi/seeInPopup.mustache +0 -8
  185. package/docs/webapi/seeInSource.mustache +0 -7
  186. package/docs/webapi/seeInTitle.mustache +0 -8
  187. package/docs/webapi/seeNumberOfElements.mustache +0 -11
  188. package/docs/webapi/seeNumberOfVisibleElements.mustache +0 -10
  189. package/docs/webapi/seeTextEquals.mustache +0 -9
  190. package/docs/webapi/seeTitleEquals.mustache +0 -8
  191. package/docs/webapi/seeTraffic.mustache +0 -36
  192. package/docs/webapi/selectOption.mustache +0 -26
  193. package/docs/webapi/setCookie.mustache +0 -16
  194. package/docs/webapi/setGeoLocation.mustache +0 -12
  195. package/docs/webapi/startRecordingTraffic.mustache +0 -8
  196. package/docs/webapi/startRecordingWebSocketMessages.mustache +0 -8
  197. package/docs/webapi/stopRecordingTraffic.mustache +0 -5
  198. package/docs/webapi/stopRecordingWebSocketMessages.mustache +0 -7
  199. package/docs/webapi/switchTo.mustache +0 -9
  200. package/docs/webapi/switchToNextTab.mustache +0 -10
  201. package/docs/webapi/switchToPreviousTab.mustache +0 -10
  202. package/docs/webapi/type.mustache +0 -21
  203. package/docs/webapi/uncheckOption.mustache +0 -13
  204. package/docs/webapi/wait.mustache +0 -8
  205. package/docs/webapi/waitForClickable.mustache +0 -11
  206. package/docs/webapi/waitForCookie.mustache +0 -9
  207. package/docs/webapi/waitForDetached.mustache +0 -10
  208. package/docs/webapi/waitForDisabled.mustache +0 -6
  209. package/docs/webapi/waitForElement.mustache +0 -11
  210. package/docs/webapi/waitForEnabled.mustache +0 -6
  211. package/docs/webapi/waitForFunction.mustache +0 -17
  212. package/docs/webapi/waitForInvisible.mustache +0 -10
  213. package/docs/webapi/waitForNumberOfTabs.mustache +0 -9
  214. package/docs/webapi/waitForText.mustache +0 -13
  215. package/docs/webapi/waitForValue.mustache +0 -10
  216. package/docs/webapi/waitForVisible.mustache +0 -10
  217. package/docs/webapi/waitInUrl.mustache +0 -9
  218. package/docs/webapi/waitNumberOfVisibleElements.mustache +0 -10
  219. package/docs/webapi/waitToHide.mustache +0 -10
  220. package/docs/webapi/waitUrlEquals.mustache +0 -10
package/docs/els.md ADDED
@@ -0,0 +1,328 @@
1
+ ## Element Access
2
+
3
+ The `els` module provides low-level element manipulation functions for CodeceptJS tests, allowing for more granular control over element interactions and assertions. Elements are wrapped in a unified `WebElement` class that provides a consistent API across all helpers (Playwright, WebDriver, Puppeteer).
4
+
5
+ > **Note:** For a comprehensive guide on element-based testing patterns and best practices, see [Element-Based Testing](element-based-testing.md).
6
+
7
+ ### Usage
8
+
9
+ Import the els functions in your test file:
10
+
11
+ ```js
12
+ import { element, eachElement, expectElement, expectAnyElement, expectAllElements } from 'codeceptjs/els'
13
+ ```
14
+
15
+ ## element
16
+
17
+ The `element` function allows you to perform custom operations on the first matching element found by a locator. It provides a low-level way to interact with elements when the built-in helper methods aren't sufficient.
18
+
19
+ ### Syntax
20
+
21
+ ```js
22
+ element(purpose, locator, fn);
23
+ // or
24
+ element(locator, fn);
25
+ ```
26
+
27
+ ### Parameters
28
+
29
+ - `purpose` (optional) - A string describing the operation being performed. If omitted, a default purpose will be generated from the function.
30
+ - `locator` - A locator string/object to find the element(s).
31
+ - `fn` - An async function that receives the element as its argument and performs the desired operation. `el` argument is a `WebElement` wrapper providing a consistent API across all helpers.
32
+
33
+ ### Returns
34
+
35
+ Returns the result of the provided async function executed on the first matching element.
36
+
37
+ ### Example
38
+
39
+ ```js
40
+ Scenario('my test', async ({ I }) => {
41
+ // combine element function with standard steps:
42
+ I.amOnPage('/cart');
43
+
44
+ // but use await every time you use element function
45
+ await element(
46
+ // with explicit purpose
47
+ 'check custom attribute',
48
+ '.button',
49
+ async el => await el.getAttribute('data-test'),
50
+ );
51
+
52
+ // or simply
53
+ await element('.button', async el => {
54
+ return await el.isEnabled();
55
+ });
56
+ });
57
+ ```
58
+
59
+ ### Notes
60
+
61
+ - Only works with helpers that implement the `_locate` method
62
+ - The function will only operate on the first element found, even if multiple elements match the locator
63
+ - The provided callback must be an async function
64
+ - Throws an error if no helper with `_locate` method is enabled
65
+
66
+ ## eachElement
67
+
68
+ The `eachElement` function allows you to perform operations on each element that matches a locator. It's useful for iterating through multiple elements and performing the same operation on each one.
69
+
70
+ ### Syntax
71
+
72
+ ```js
73
+ eachElement(purpose, locator, fn);
74
+ // or
75
+ eachElement(locator, fn);
76
+ ```
77
+
78
+ ### Parameters
79
+
80
+ - `purpose` (optional) - A string describing the operation being performed. If omitted, a default purpose will be generated from the function.
81
+ - `locator` - A locator string/object to find the element(s).
82
+ - `fn` - An async function that receives two arguments:
83
+ - `el` - The current element being processed
84
+ - `index` - The index of the current element in the collection
85
+
86
+ ### Returns
87
+
88
+ Returns a promise that resolves when all elements have been processed. If any element operation fails, the function will throw the first encountered error.
89
+
90
+ ### Example
91
+
92
+ ```js
93
+ Scenario('my test', async ({ I }) => {
94
+ // combine element function with standard steps:
95
+ I.click('/hotels');
96
+
97
+ // iterate over elements but don't forget to put await
98
+ await eachElement(
99
+ 'validate list items', // explain your actions for future review
100
+ '.list-item', // locator
101
+ async (el, index) => {
102
+ const text = await el.getText();
103
+ console.log(`Item ${index}: ${text}`);
104
+ },
105
+ );
106
+
107
+ // Or simply check if all checkboxes are checked
108
+ await eachElement('input[type="checkbox"]', async el => {
109
+ const checked = await el.getProperty('checked');
110
+ if (!checked) {
111
+ throw new Error('Found unchecked checkbox');
112
+ }
113
+ });
114
+ });
115
+ ```
116
+
117
+ ### Notes
118
+
119
+ - Only works with helpers that implement the `_locate` method
120
+ - The function will process all elements that match the locator
121
+ - The provided callback must be an async function
122
+ - If an operation fails on any element, the error is logged and the function continues processing remaining elements
123
+ - After all elements are processed, if any errors occurred, the first error is thrown
124
+ - Throws an error if no helper with `_locate` method is enabled
125
+
126
+ ## expectElement
127
+
128
+ The `expectElement` function allows you to perform assertions on the first element that matches a locator. It's designed for validating element properties or states and will throw an assertion error if the condition is not met.
129
+
130
+ ### Syntax
131
+
132
+ ```js
133
+ expectElement(locator, fn);
134
+ ```
135
+
136
+ ### Parameters
137
+
138
+ - `locator` - A locator string/object to find the element(s).
139
+ - `fn` - An async function that receives the element as its argument and should return a boolean value:
140
+ - `true` - The assertion passed
141
+ - `false` - The assertion failed
142
+
143
+ ### Returns
144
+
145
+ Returns a promise that resolves when the assertion is complete. Throws an assertion error if the condition is not met.
146
+
147
+ ### Example
148
+
149
+ ```js
150
+ // Check if a button is enabled
151
+ await expectElement('.submit-button', async el => {
152
+ return await el.isEnabled();
153
+ });
154
+
155
+ // Verify element has specific text content
156
+ await expectElement('.header', async el => {
157
+ const text = await el.getText();
158
+ return text === 'Welcome';
159
+ });
160
+
161
+ // Check for specific attribute value
162
+ await expectElement('#user-profile', async el => {
163
+ const role = await el.getAttribute('role');
164
+ return role === 'button';
165
+ });
166
+ ```
167
+
168
+ ### Notes
169
+
170
+ - Only works with helpers that implement the `_locate` method
171
+ - The function will only check the first element found, even if multiple elements match the locator
172
+ - The provided callback must be an async function that returns a boolean
173
+ - The assertion message will include both the locator and the function used for validation
174
+ - Throws an error if no helper with `_locate` method is enabled
175
+
176
+ ## expectAnyElement
177
+
178
+ The `expectAnyElement` function allows you to perform assertions where at least one element from a collection should satisfy the condition. It's useful when you need to verify that at least one element among many matches your criteria.
179
+
180
+ ### Syntax
181
+
182
+ ```js
183
+ expectAnyElement(locator, fn);
184
+ ```
185
+
186
+ ### Parameters
187
+
188
+ - `locator` - A locator string/object to find the element(s).
189
+ - `fn` - An async function that receives the element as its argument and should return a boolean value:
190
+ - `true` - The assertion passed for this element
191
+ - `false` - The assertion failed for this element
192
+
193
+ ### Returns
194
+
195
+ Returns a promise that resolves when the assertion is complete. Throws an assertion error if no elements satisfy the condition.
196
+
197
+ ### Example
198
+
199
+ ```js
200
+ Scenario('validate any element matches criteria', async ({ I }) => {
201
+ // Navigate to the page
202
+ I.amOnPage('/products');
203
+
204
+ // Check if any product is marked as "in stock"
205
+ await expectAnyElement('.product-item', async el => {
206
+ const status = await el.getAttribute('data-status');
207
+ return status === 'in-stock';
208
+ });
209
+
210
+ // Verify at least one price is below $100
211
+ await expectAnyElement('.price-tag', async el => {
212
+ const price = await el.getText();
213
+ return parseFloat(price.replace('$', '')) < 100;
214
+ });
215
+
216
+ // Check if any button in the list is enabled
217
+ await expectAnyElement('.action-button', async el => {
218
+ return await el.isEnabled();
219
+ });
220
+ });
221
+ ```
222
+
223
+ ### Notes
224
+
225
+ - Only works with helpers that implement the `_locate` method
226
+ - The function will check all matching elements until it finds one that satisfies the condition
227
+ - Stops checking elements once the first matching condition is found
228
+ - The provided callback must be an async function that returns a boolean
229
+ - Throws an assertion error if no elements satisfy the condition
230
+ - Throws an error if no helper with `_locate` method is enabled
231
+
232
+ ## expectAllElements
233
+
234
+ The `expectAllElements` function verifies that every element matching the locator satisfies the given condition. It's useful when you need to ensure that all elements in a collection meet specific criteria.
235
+
236
+ ### Syntax
237
+
238
+ ```js
239
+ expectAllElements(locator, fn);
240
+ ```
241
+
242
+ ### Parameters
243
+
244
+ - `locator` - A locator string/object to find the element(s).
245
+ - `fn` - An async function that receives the element as its argument and should return a boolean value:
246
+ - `true` - The assertion passed for this element
247
+ - `false` - The assertion failed for this element
248
+
249
+ ### Returns
250
+
251
+ Returns a promise that resolves when all assertions are complete. Throws an assertion error as soon as any element fails the condition.
252
+
253
+ ### Example
254
+
255
+ ```js
256
+ Scenario('validate all elements meet criteria', async ({ I }) => {
257
+ // Navigate to the page
258
+ I.amOnPage('/dashboard');
259
+
260
+ // Verify all required fields have the required attribute
261
+ await expectAllElements('.required-field', async el => {
262
+ const required = await el.getAttribute('required');
263
+ return required !== null;
264
+ });
265
+
266
+ // Check if all checkboxes in a form are checked
267
+ await expectAllElements('input[type="checkbox"]', async el => {
268
+ const checked = await el.getProperty('checked');
269
+ return checked === true;
270
+ });
271
+
272
+ // Verify all items in a list have non-empty text
273
+ await expectAllElements('.list-item', async el => {
274
+ const text = await el.getText();
275
+ return text.trim().length > 0;
276
+ });
277
+
278
+ // Ensure all buttons in a section are enabled
279
+ await expectAllElements('#action-section button', async el => {
280
+ return await el.isEnabled();
281
+ });
282
+ });
283
+ ```
284
+
285
+ ### Notes
286
+
287
+ - Only works with helpers that implement the `_locate` method
288
+ - The function checks every element that matches the locator
289
+ - Fails fast: stops checking elements as soon as one fails the condition
290
+ - The provided callback must be an async function that returns a boolean
291
+ - The assertion message will include which element number failed (e.g., "element #2 of...")
292
+ - Throws an error if no helper with `_locate` method is enabled
293
+
294
+ ## WebElement API
295
+
296
+ Elements passed to your callbacks are wrapped in a `WebElement` class that provides a consistent API across all helpers. For complete documentation of the WebElement API, see [WebElement](WebElement.md).
297
+
298
+ Quick reference of available methods:
299
+
300
+ ```js
301
+ await element('.my-element', async el => {
302
+ // Get element information
303
+ const text = await el.getText()
304
+ const attr = await el.getAttribute('data-value')
305
+ const prop = await el.getProperty('value')
306
+ const html = await el.getInnerHTML()
307
+
308
+ // Check state
309
+ const visible = await el.isVisible()
310
+ const enabled = await el.isEnabled()
311
+ const exists = await el.exists()
312
+
313
+ // Interactions
314
+ await el.click()
315
+ await el.type('text')
316
+
317
+ // Child elements
318
+ const child = await el.$('.child')
319
+ const children = await el.$$('.child')
320
+
321
+ // Position
322
+ const box = await el.getBoundingBox()
323
+
324
+ // Native access
325
+ const helper = el.getHelper()
326
+ const native = el.getNativeElement()
327
+ })
328
+ ```
@@ -0,0 +1,161 @@
1
+ ---
2
+ permalink: /examples
3
+ layout: Section
4
+ sidebar: false
5
+ title: Examples
6
+ editLink: false
7
+ ---
8
+
9
+ # Examples
10
+
11
+ > Add your own examples to our [Wiki Page](https://github.com/codeceptjs/CodeceptJS/wiki/Examples)
12
+
13
+ ## [TodoMVC Examples](https://github.com/codecept-js/examples)
14
+
15
+ ![](https://github.com/codecept-js/examples/raw/master/todo.png)
16
+
17
+ Playground repository where you can run tests in different helpers on a basic single-page website.
18
+
19
+ Tests repository demonstrate usage of
20
+
21
+ - Playwright helper
22
+ - Puppeteer helper
23
+ - WebDriver helper
24
+ - Toggle headless mode with env variables
25
+ - PageObjects
26
+ - Cucumber syntax
27
+
28
+ ## [Basic Examples](https://github.com/Codeception/CodeceptJS/tree/master/examples)
29
+
30
+ CodeceptJS repo contains basic tests (both failing and passing) just to show how it works.
31
+ Our team uses it to test new features and run simple scenarios.
32
+
33
+ ## [CodeceptJS Cucumber E2E Framework](https://github.com/gkushang/codeceptjs-e2e)
34
+
35
+ This repository contains complete E2E framework for CodeceptJS with Cucumber and SauceLabs Integration
36
+
37
+ - CodecepJS-Cucumber E2E Framework
38
+ - Saucelabs Integration
39
+ - Run Cross Browser tests in Parallel on SauceLabs with a simple command
40
+ - Run tests on `chrome:headless`
41
+ - Page Objects
42
+ - `Should.js` Assertion Library
43
+ - Uses `wdio` service (selenium-standalone, sauce)
44
+ - Allure HTML Reports
45
+ - Uses shared Master configuration
46
+ - Sample example and feature files of GitHub Features
47
+
48
+ ## [Enterprise Grade Tests](https://github.com/uc-cdis/gen3-qa)
49
+
50
+ Complex testing solution by [Gen3](https://github.com/uc-cdis/gen3-qa)
51
+
52
+ Includes
53
+
54
+ - classical CodeceptJS tests
55
+ - BDD tests
56
+ - Jenkins integration
57
+ - Complex Before/BeforeSuite scripts and more
58
+
59
+ ## [Testing Single Page Application](https://github.com/bugiratracker/codeceptjs-demo)
60
+
61
+ End 2 end tests for Task management app (currently offline).
62
+
63
+ Tests repository demonstrate usage of
64
+
65
+ - Puppeteer helper
66
+ - ApiDataFactory helper
67
+ - autoLogin plugin
68
+ - Dynamic config with profiles
69
+
70
+ ## [Practical E2E Tests](https://gitlab.com/paulvincent/codeceptjs-e2e-testing)
71
+
72
+ Examples from the book [Practical End 2 End Testing with CodeceptJS](https://leanpub.com/codeceptjs/) by **Paul Vincent Beigang**.
73
+
74
+ This repository demonstrates usage of:
75
+
76
+ - dynamic config with profiles
77
+ - testing WYSIWYG editor
78
+ - GitLab CI
79
+
80
+ ## [Amazon Tests v2](https://gitlab.com/thanhnguyendh/codeceptjs-wdio-services)
81
+
82
+ Testing Amazon website using Selenium WebDriver.
83
+
84
+ This repository demonstrates usage of:
85
+
86
+ - WebDriver helper
87
+ - Page Objects
88
+ - wdio services (selenium-standalone)
89
+ - Parallel execution
90
+ - GitLab CI setup
91
+
92
+ ## [Tests with Docker Compose](https://github.com/mathesouza/codeceptjs-docker-compose)
93
+
94
+ Running CodeceptJS tests with Docker Compose
95
+
96
+ This repository demonstrates usage of:
97
+
98
+ - CodeceptJS Docker image
99
+ - WebDriver helper
100
+ - Allure plugin
101
+
102
+ ## [AngularJS Example Tests](https://github.com/armno/angular-e2e-codeceptjs-example)
103
+
104
+ Based on [Setting up End-to-End Testing in Angular Project with CodeceptJS](https://medium.com/@armno/setting-up-end-to-end-testing-in-angular-project-with-codeceptjs-ac1784de3420) post by Armno Prommarak.
105
+
106
+ This repository demonstrates usage of
107
+
108
+ - Puppeteer helper
109
+ - Working with Angular CLI
110
+ - Reports with Mochawesome helper
111
+
112
+ ## [REST Example Tests](https://github.com/PeterNgTr/codeceptjs-rest-demo)
113
+
114
+ This repository demonstrates usage of
115
+
116
+ - REST helper
117
+
118
+ ## [Automation Starter](https://github.com/sjorrillo/automation-starter)
119
+
120
+ The purpose of this application is for learning the basics and how to use good practices and useful tools in automation.
121
+
122
+ - Puppeteer helper
123
+ - Working with gherkin, also it has type definitions and to be able to use them inside when, given and then make sure you add `declare function inject(): { I: CodeceptJS.I, [key: string]: any; };`in the `steps.d.ts`file
124
+ - Linting `airbnb-base`, `codeceptjs/codeceptjs` and full ES6 support
125
+
126
+ ## [Example for using: Puppeteer, Gherkin, Allure with parallel execution](https://github.com/SchnuckySchuster/codeceptJSExample)
127
+
128
+ This is a ready to use example that shows how to integrate CodeceptJS with Puppeteer and Allure as reporting tool.
129
+
130
+ - detailed ReadMe
131
+ - tests written in cucumber alongside tests written in the codeceptJS DSL
132
+ - puppeteer helper example
133
+ - test steps, pages, fragments
134
+ - examples for sequential and parallel execution
135
+ - generation of allure test results
136
+
137
+ ## [Example for Advanced REST API testing: TypeScript, Axios, CodeceptJS, Jest Expect, Docker, Allure, Mock-Server, Prettier + Eslint, pre-commit, Jest Unit Tests ](https://github.com/EgorBodnar/rest-axios-codeceptjs-allure-docker-test-example)
138
+
139
+ One button example with built-in mocked backend.
140
+
141
+ If you already have a UI testing solution based on the CodeceptJS and you need to implement advanced REST API testing you can just extend your existing framework. Use this implementation as an example.
142
+ This is necessary if all integrations with TMS and CI/CD are already configured, and you do not want to reconnect and configure the plugins and libraries used for the new test runner. Use CodeceptJS!
143
+
144
+ - Easy run
145
+ - Detailed README
146
+ - Well documented mocked backend's REST API endpoints
147
+ - HTTP request client with session support and unit tests
148
+ - Exemplary code control
149
+ - Ready to launch in a CI/CD system as is
150
+ - OOP, Test data models and builders, endpoint decorators
151
+
152
+ ## [Playwright fun with CodeceptJS](https://github.com/PeterNgTr/codeceptjs-playwright-fun)
153
+
154
+ - Tests are written in TS
155
+ - CI/CD with Github Actions
156
+ - Page Object Model is applied
157
+ - ReportPortal Integration
158
+
159
+ ## How to
160
+
161
+ - Create a plugin with TS [link](https://github.com/reutenkoivan/codeceptjs-plugins/tree/main/packages/html-snapshot-on-fail)
package/docs/heal.md ADDED
@@ -0,0 +1,213 @@
1
+ # Self-Healing Tests
2
+
3
+ Browser and Mobile tests can fail for vareity of reasons. However, on a big projects there are about 5-10 causes of flaky tests. The more you work and understand your end-to-end tests the more you learn patterns of failure. And after the research you understand how a test could have been fixed: to reload a page, to click that button once again, restart API request. If by looking into a failure you understand what, as a user, you would do to fix that error, then maybe you could teach your tests to heal themselves.
4
+
5
+ ## What is Healing
6
+
7
+ **Healing defines the way how a test reacts to failure**. You can define multiple healing recipes that could take all needed information: error message, failed test, step, page URL, HTML, etc. A healing recipe can perform some action to fix the failing test on the fly and continue its execution.
8
+
9
+ ![](/img/healing.png)
10
+
11
+ Let's start with a common scenario. If a user suddenly becomes unauthorized and is moved to a sign-in page, or receives an unauthorized message on the page, we can heal by navigating to the `/login` page and trying to enter credentials again.
12
+
13
+ ```js
14
+ heal.addRecipe('loginOnUnauthorized', {
15
+ priority: 10,
16
+ steps: ['click', 'see', 'amOnPage'],
17
+ prepare: {
18
+ url: ({ I }) => I.grabCurrentUrl(),
19
+ html: ({ I }) => I.grabHTMLFrom('body'),
20
+ },
21
+ fn: async ({ url, error, step, html }) => {
22
+ if (!url.includes('/login') && !error.message.toLowerCase().includes('unauthorized') && !html.toLowerCase().includes('unauthorized')) return;
23
+
24
+ return ({ I }) => {
25
+ I.amOnPage('/login');
26
+ I.fillField('Email', 'test@example.com');
27
+ I.fillField('Password', '123456');
28
+ I.click('Sign in');
29
+ I[step.name](...step.args);
30
+ };
31
+ },
32
+ });
33
+ ```
34
+
35
+ Another example is a very basic healing recipe. If after a click test has failed, try to reload page, and continue.
36
+
37
+ ```js
38
+ heal.addRecipe('reload', {
39
+ priority: 10,
40
+ steps: ['click'],
41
+ fn: async ({ step }) => {
42
+ return ({ I }) => {
43
+ I.refreshPage();
44
+ I[step.name](...step.args);
45
+ };
46
+ },
47
+ });
48
+ ```
49
+
50
+ Sure, this won't always work and probably won't be useful on every project. But let's follow the idea: if a click has failed, probably the button is not on a page, maybe it is an issue of rendering, maybe some other element overlapped our button, so if we try to reload page we can continue test execution. At least, this is what manual QA would do if they will run the following test in a browser. They will try to reload a page before reporting "it has failed".
51
+
52
+ So if it is a long end-2-end test that implements user journey, it is more valuable to continue its execution when possible, then fixing a minor issues like overlapping elements. Healing like this can improve the stability of a test.
53
+
54
+ The example above is only one way a test can be healed. But you can define as many heal recipes as you like. What heal recipe would be effective in your case is depends on a system you test, so **there are no pre-defined heal recipes**.
55
+
56
+ ## Healing Patterns
57
+
58
+ There are some ideas where healing can be useful to you:
59
+
60
+ * **Authorization**. If a user suddenly becomes unauthorized and is moved to a sign-in page, or receives an unauthorized message on the page, we can heal by navigating to the `/login` page and trying to enter credentials.
61
+ * **Networking**. If a test depends on a remote resource, and fails because this resource is not available, you may try to send API request to restore that resource before throwing an error.
62
+ * **Data Consistency**. A test may fail because you noticed the data glitch in a system. Instead of failing a test you may try to clean up the data and try again to proceed.
63
+ * **UI Change**. If there is a planned UI migration of a component, for instance Button was changed to Dropdown. You can prepare test so if it fails clicking Button it can try to do so with Dropdown.
64
+ * **Do it again**. If you know, that going one step back and trying to do same actions may solve the issue, you can do so from healers. For instance, a modal didn't render correctly, so you can close it and try to click to open it again.
65
+
66
+ ## Healing vs Retries
67
+
68
+ Unlike retries heal recipes has following benefits:
69
+
70
+ * Heal recipes are **declarative**, they are not added directly into into the test code. This keeps test clean and scenario-focused,
71
+ * Retry can only re-run failed step(s), but heal recipe can **perform wide set of actions**
72
+ * Heal recipe **can react to any step of any test**. So if you catch a common error and you can heal it, you won't need to guess where it can be thrown.
73
+
74
+ ## How to Start Healing
75
+
76
+ To enable healing, you need to define healing recipes and enable heal plugin.
77
+
78
+ Create basic healing recipes using this command:
79
+
80
+ ```
81
+ npx codeceptjs generate:heal
82
+ ```
83
+
84
+ or
85
+
86
+ ```
87
+ npx codeceptjs gr
88
+ ```
89
+
90
+ this will generate `recipes.js` (or `recipes.ts`) in the root directory. Provided default recipe include [AI healing](#ai-healing) and `clickAndType` recipe that replaces `fillField` with `click`+`type`. Use them as examples to write your own heal recipes that will fit for application you are testing.
91
+
92
+ Require `recipes` file and add `heal` plugin to `codecept.conf` file:
93
+
94
+ ```js
95
+
96
+ import './heal';
97
+
98
+ export const config = {
99
+ // ...
100
+ plugins: {
101
+ heal: {
102
+ enabled: true
103
+ }
104
+ }
105
+ }
106
+ ```
107
+
108
+ > Please note that, healing has no sense while developing tests, so it won't work in `--debug` mode.
109
+
110
+ ## Writing Recipes
111
+
112
+ Custom heal recipes can be added by running `heal.addRecipe()` function. By default it should be added to `recipes.js` (or `recipes.ts`) file.
113
+
114
+ Let's see what recipe consist of:
115
+
116
+ ```js
117
+ heal.addRecipe('reloadPageOnUserAccount', {
118
+ // recipe priority
119
+ // which recipe should be tried first
120
+ priority: 10,
121
+
122
+ // an array of steps which may cause the error
123
+ // after which a recipe should be activate
124
+ steps: [
125
+ 'click',
126
+ ],
127
+
128
+ // if you need some additional information like URL of a page,
129
+ // or its HTML, you can add this context to healing function by
130
+ // defining `prepare` list of variable
131
+ prepare: {
132
+ url: ({ I }) => I.grabCurrentUrl(),
133
+ html: ({ I }) => I.grabHTMLFrom('body'),
134
+ // don't add variables that you won't use inside the recipe
135
+ },
136
+
137
+ // probably we want to execute recipes only on some tests
138
+ // so you can set a string or regex which will check if a test title matches the name
139
+ // in this case we execute recipe only on tests that have "@flaky" in their name
140
+ grep: '@flaky',
141
+
142
+ // function to launch healing process
143
+ fn: async ({
144
+ // standard context variables
145
+ step, test, error, prevSteps,
146
+
147
+ // variables coming from prepare function
148
+ html, url,
149
+
150
+ }) => {
151
+ const stepArgs = step.args;
152
+
153
+ // at this point we can decide, should we provide a healing recipe or not
154
+ // for instance, if URL is not the one we can heal at, we should not provide any recipes
155
+ if (!url.includes('/user/acccount')) return;
156
+
157
+ // otherwise we return a function that will be executed
158
+ return ({ I }) => {
159
+ // this is a very basic example action
160
+ // probably you should do something more sophisticated
161
+ // to heal the test
162
+ I.reloadPage();
163
+ I.wait(1);
164
+ I[step.name](...stepArgs);
165
+ };
166
+ },
167
+ });
168
+ ```
169
+
170
+ Let's briefly sum up the properties of a recipe:
171
+
172
+ * `grep` - selects tests by their name to apply heal to
173
+ * `steps` - defines on which steps a recipe should react
174
+ * `priority` - sets the order of recipes being applied
175
+ * `prepare` - declare variables from a context, which can be used for healing
176
+ * `fn` - a function to be applied for healing. It takes all context params: `test`, `step`, `error`, `prevSteps` and returns return either a function or a markdown text with recipes (used by AI healers). If no recipes match the context should not return anything;
177
+
178
+
179
+ ## AI Healing
180
+
181
+ AI can be used to heal failed tests. Large Language Models can analyze HTML of a failed test and provide a suggestion what actions should be performed instead. This can be helpful when running tests on CI as AI can make basic decisions to stabilize failing tests.
182
+
183
+ > Use **OpenAI, Azure OpenAI, Claude**, or any of other LLM that can take a prompt, analyze request and provide valid JS code which can be executed by CodeceptJS as a healing suggestion.
184
+
185
+ AI healing recipe is created within `recipes.js` file:
186
+
187
+ ```js
188
+ heal.addRecipe('ai', {
189
+ priority: 10,
190
+ prepare: {
191
+ html: ({ I }) => I.grabHTMLFrom('body'),
192
+ },
193
+ steps: [
194
+ 'click',
195
+ 'fillField',
196
+ 'appendField',
197
+ 'selectOption',
198
+ 'attachFile',
199
+ 'checkOption',
200
+ 'uncheckOption',
201
+ 'doubleClick',
202
+ ],
203
+ fn: async (args) => {
204
+ return ai.healFailedStep(args);
205
+ },
206
+ });
207
+ ```
208
+
209
+ As you use, it will be activated on failed steps and will use HTML of a page as additional information. The prompt, error, and the HTML will be sent to AI provider you configured.
210
+
211
+ Learn more how you can [configure AI provider](./ai).
212
+
213
+ To activate the AI healer don't forget to run tests with `--ai` flag.