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

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (294) hide show
  1. package/README.md +39 -27
  2. package/bin/codecept.js +15 -2
  3. package/bin/codeceptq.js +49 -0
  4. package/bin/mcp-server.js +1187 -0
  5. package/docs/advanced.md +201 -0
  6. package/docs/agents.md +159 -0
  7. package/docs/ai.md +537 -0
  8. package/docs/aitrace.md +266 -0
  9. package/docs/api.md +332 -0
  10. package/docs/assertions.md +415 -0
  11. package/docs/auth.md +318 -0
  12. package/docs/basics.md +424 -0
  13. package/docs/bdd.md +539 -0
  14. package/docs/best.md +240 -0
  15. package/docs/bootstrap.md +132 -0
  16. package/docs/commands.md +352 -0
  17. package/docs/community-helpers.md +63 -0
  18. package/docs/configuration.md +230 -0
  19. package/docs/continuous-integration.md +497 -0
  20. package/docs/custom-helpers.md +297 -0
  21. package/docs/data.md +448 -0
  22. package/docs/debugging.md +332 -0
  23. package/docs/detox.md +235 -0
  24. package/docs/docker.md +136 -0
  25. package/docs/effects.md +179 -0
  26. package/docs/element-based-testing.md +295 -0
  27. package/docs/element-selection.md +125 -0
  28. package/docs/els.md +328 -0
  29. package/docs/examples.md +161 -0
  30. package/docs/heal.md +213 -0
  31. package/docs/helpers/ApiDataFactory.md +267 -0
  32. package/docs/helpers/Appium.md +1405 -0
  33. package/docs/helpers/Detox.md +665 -0
  34. package/docs/helpers/ExpectHelper.md +275 -0
  35. package/docs/helpers/FileSystem.md +152 -0
  36. package/docs/helpers/GraphQL.md +152 -0
  37. package/docs/helpers/GraphQLDataFactory.md +226 -0
  38. package/docs/helpers/JSONResponse.md +255 -0
  39. package/docs/helpers/Mochawesome.md +8 -0
  40. package/docs/helpers/MockRequest.md +377 -0
  41. package/docs/helpers/MockServer.md +212 -0
  42. package/docs/helpers/Playwright.md +2969 -0
  43. package/docs/helpers/Polly.md +44 -0
  44. package/docs/helpers/Protractor.md +1769 -0
  45. package/docs/helpers/Puppeteer-firefox.md +86 -0
  46. package/docs/helpers/Puppeteer.md +2690 -0
  47. package/docs/helpers/REST.md +289 -0
  48. package/docs/helpers/SoftExpectHelper.md +352 -0
  49. package/docs/helpers/WebDriver.md +2682 -0
  50. package/docs/hooks.md +339 -0
  51. package/docs/index.md +111 -0
  52. package/docs/installation.md +83 -0
  53. package/docs/internal-api.md +265 -0
  54. package/docs/internal-test-server.md +89 -0
  55. package/docs/locators.md +355 -0
  56. package/docs/mcp.md +485 -0
  57. package/docs/migration-4.md +556 -0
  58. package/docs/mobile.md +338 -0
  59. package/docs/pageobjects.md +399 -0
  60. package/docs/parallel.md +585 -0
  61. package/docs/playwright.md +714 -0
  62. package/docs/plugins.md +866 -0
  63. package/docs/puppeteer.md +314 -0
  64. package/docs/quickstart.md +120 -0
  65. package/docs/react.md +70 -0
  66. package/docs/reports.md +483 -0
  67. package/docs/retry.md +274 -0
  68. package/docs/secrets.md +150 -0
  69. package/docs/sessions.md +80 -0
  70. package/docs/shadow.md +68 -0
  71. package/docs/test-structure.md +275 -0
  72. package/docs/timeouts.md +183 -0
  73. package/docs/translation.md +247 -0
  74. package/docs/tutorial.md +271 -0
  75. package/docs/typescript.md +374 -0
  76. package/docs/web-element.md +251 -0
  77. package/docs/webdriver.md +708 -0
  78. package/docs/within.md +55 -0
  79. package/lib/ai.js +3 -2
  80. package/lib/aria.js +260 -0
  81. package/lib/assertions.js +18 -0
  82. package/lib/codecept.js +26 -23
  83. package/lib/command/check.js +2 -1
  84. package/lib/command/dryRun.js +24 -5
  85. package/lib/command/generate.js +2 -0
  86. package/lib/command/gherkin/snippets.js +5 -4
  87. package/lib/command/init.js +248 -269
  88. package/lib/command/list.js +150 -10
  89. package/lib/command/query.js +218 -0
  90. package/lib/command/run-multiple.js +2 -0
  91. package/lib/command/run-workers.js +2 -0
  92. package/lib/command/run.js +1 -1
  93. package/lib/command/workers/runTests.js +10 -10
  94. package/lib/config.js +77 -4
  95. package/lib/container.js +114 -17
  96. package/lib/effects.js +17 -0
  97. package/lib/element/WebElement.js +246 -2
  98. package/lib/els.js +12 -6
  99. package/lib/globals.js +32 -19
  100. package/lib/heal.js +4 -3
  101. package/lib/helper/ApiDataFactory.js +2 -1
  102. package/lib/helper/Appium.js +8 -8
  103. package/lib/helper/FileSystem.js +3 -2
  104. package/lib/helper/GraphQLDataFactory.js +2 -1
  105. package/lib/helper/Playwright.js +228 -162
  106. package/lib/helper/Puppeteer.js +208 -76
  107. package/lib/helper/WebDriver.js +173 -68
  108. package/lib/helper/errors/MultipleElementsFound.js +27 -110
  109. package/lib/helper/errors/NonFocusedType.js +8 -0
  110. package/lib/helper/extras/Download.js +45 -0
  111. package/lib/helper/extras/PlaywrightReactVueLocator.js +45 -36
  112. package/lib/helper/extras/elementSelection.js +58 -0
  113. package/lib/helper/extras/focusCheck.js +43 -0
  114. package/lib/helper/extras/richTextEditor.js +178 -0
  115. package/lib/helper/scripts/dropFile.js +11 -0
  116. package/lib/history.js +3 -2
  117. package/lib/html.js +103 -16
  118. package/lib/index.js +9 -1
  119. package/lib/listener/config.js +6 -4
  120. package/lib/listener/emptyRun.js +2 -1
  121. package/lib/listener/globalRetry.js +32 -6
  122. package/lib/listener/helpers.js +4 -1
  123. package/lib/listener/mocha.js +2 -1
  124. package/lib/listener/pageobjects.js +43 -0
  125. package/lib/listener/result.js +3 -2
  126. package/lib/locator.js +126 -3
  127. package/lib/mocha/cli.js +14 -2
  128. package/lib/mocha/factory.js +7 -2
  129. package/lib/mocha/inject.js +1 -1
  130. package/lib/mocha/scenarioConfig.js +2 -1
  131. package/lib/mocha/ui.js +5 -6
  132. package/lib/parser.js +2 -2
  133. package/lib/pause.js +38 -4
  134. package/lib/plugin/aiTrace.js +453 -0
  135. package/lib/plugin/analyze.js +1 -1
  136. package/lib/plugin/auth.js +3 -3
  137. package/lib/plugin/browser.js +77 -0
  138. package/lib/plugin/expose.js +159 -0
  139. package/lib/plugin/heal.js +44 -1
  140. package/lib/plugin/pageInfo.js +53 -49
  141. package/lib/plugin/pause.js +131 -0
  142. package/lib/plugin/pauseOnFail.js +10 -34
  143. package/lib/plugin/retryFailedStep.js +28 -19
  144. package/lib/plugin/screencast.js +287 -0
  145. package/lib/plugin/screenshot.js +563 -0
  146. package/lib/plugin/screenshotOnFail.js +8 -171
  147. package/lib/rerun.js +2 -1
  148. package/lib/result.js +2 -1
  149. package/lib/step/base.js +3 -2
  150. package/lib/step/config.js +15 -2
  151. package/lib/step/record.js +2 -2
  152. package/lib/store.js +72 -3
  153. package/lib/translation.js +2 -1
  154. package/lib/utils/mask_data.js +2 -1
  155. package/lib/utils/pluginParser.js +151 -0
  156. package/lib/utils/trace.js +297 -0
  157. package/lib/utils.js +77 -3
  158. package/lib/workers.js +52 -22
  159. package/package.json +19 -13
  160. package/typings/index.d.ts +19 -5
  161. package/docs/webapi/amOnPage.mustache +0 -11
  162. package/docs/webapi/appendField.mustache +0 -11
  163. package/docs/webapi/attachFile.mustache +0 -12
  164. package/docs/webapi/blur.mustache +0 -18
  165. package/docs/webapi/checkOption.mustache +0 -13
  166. package/docs/webapi/clearCookie.mustache +0 -9
  167. package/docs/webapi/clearField.mustache +0 -9
  168. package/docs/webapi/click.mustache +0 -29
  169. package/docs/webapi/clickLink.mustache +0 -8
  170. package/docs/webapi/closeCurrentTab.mustache +0 -7
  171. package/docs/webapi/closeOtherTabs.mustache +0 -8
  172. package/docs/webapi/dontSee.mustache +0 -11
  173. package/docs/webapi/dontSeeCheckboxIsChecked.mustache +0 -10
  174. package/docs/webapi/dontSeeCookie.mustache +0 -8
  175. package/docs/webapi/dontSeeCurrentPathEquals.mustache +0 -10
  176. package/docs/webapi/dontSeeCurrentUrlEquals.mustache +0 -10
  177. package/docs/webapi/dontSeeElement.mustache +0 -8
  178. package/docs/webapi/dontSeeElementInDOM.mustache +0 -8
  179. package/docs/webapi/dontSeeInCurrentUrl.mustache +0 -4
  180. package/docs/webapi/dontSeeInField.mustache +0 -11
  181. package/docs/webapi/dontSeeInSource.mustache +0 -8
  182. package/docs/webapi/dontSeeInTitle.mustache +0 -8
  183. package/docs/webapi/dontSeeTraffic.mustache +0 -13
  184. package/docs/webapi/doubleClick.mustache +0 -13
  185. package/docs/webapi/downloadFile.mustache +0 -12
  186. package/docs/webapi/dragAndDrop.mustache +0 -9
  187. package/docs/webapi/dragSlider.mustache +0 -11
  188. package/docs/webapi/executeAsyncScript.mustache +0 -24
  189. package/docs/webapi/executeScript.mustache +0 -26
  190. package/docs/webapi/fillField.mustache +0 -16
  191. package/docs/webapi/flushNetworkTraffics.mustache +0 -5
  192. package/docs/webapi/focus.mustache +0 -13
  193. package/docs/webapi/forceClick.mustache +0 -28
  194. package/docs/webapi/forceRightClick.mustache +0 -18
  195. package/docs/webapi/grabAllWindowHandles.mustache +0 -7
  196. package/docs/webapi/grabAttributeFrom.mustache +0 -10
  197. package/docs/webapi/grabAttributeFromAll.mustache +0 -9
  198. package/docs/webapi/grabBrowserLogs.mustache +0 -9
  199. package/docs/webapi/grabCookie.mustache +0 -11
  200. package/docs/webapi/grabCssPropertyFrom.mustache +0 -11
  201. package/docs/webapi/grabCssPropertyFromAll.mustache +0 -10
  202. package/docs/webapi/grabCurrentUrl.mustache +0 -9
  203. package/docs/webapi/grabCurrentWindowHandle.mustache +0 -6
  204. package/docs/webapi/grabDataFromPerformanceTiming.mustache +0 -20
  205. package/docs/webapi/grabElementBoundingRect.mustache +0 -20
  206. package/docs/webapi/grabGeoLocation.mustache +0 -8
  207. package/docs/webapi/grabHTMLFrom.mustache +0 -10
  208. package/docs/webapi/grabHTMLFromAll.mustache +0 -9
  209. package/docs/webapi/grabNumberOfOpenTabs.mustache +0 -8
  210. package/docs/webapi/grabNumberOfVisibleElements.mustache +0 -9
  211. package/docs/webapi/grabPageScrollPosition.mustache +0 -8
  212. package/docs/webapi/grabPopupText.mustache +0 -5
  213. package/docs/webapi/grabRecordedNetworkTraffics.mustache +0 -10
  214. package/docs/webapi/grabSource.mustache +0 -8
  215. package/docs/webapi/grabTextFrom.mustache +0 -10
  216. package/docs/webapi/grabTextFromAll.mustache +0 -9
  217. package/docs/webapi/grabTitle.mustache +0 -8
  218. package/docs/webapi/grabValueFrom.mustache +0 -9
  219. package/docs/webapi/grabValueFromAll.mustache +0 -8
  220. package/docs/webapi/grabWebElement.mustache +0 -9
  221. package/docs/webapi/grabWebElements.mustache +0 -9
  222. package/docs/webapi/moveCursorTo.mustache +0 -12
  223. package/docs/webapi/openNewTab.mustache +0 -7
  224. package/docs/webapi/pressKey.mustache +0 -12
  225. package/docs/webapi/pressKeyDown.mustache +0 -12
  226. package/docs/webapi/pressKeyUp.mustache +0 -12
  227. package/docs/webapi/pressKeyWithKeyNormalization.mustache +0 -60
  228. package/docs/webapi/refreshPage.mustache +0 -6
  229. package/docs/webapi/resizeWindow.mustache +0 -6
  230. package/docs/webapi/rightClick.mustache +0 -14
  231. package/docs/webapi/saveElementScreenshot.mustache +0 -10
  232. package/docs/webapi/saveScreenshot.mustache +0 -12
  233. package/docs/webapi/say.mustache +0 -10
  234. package/docs/webapi/scrollIntoView.mustache +0 -11
  235. package/docs/webapi/scrollPageToBottom.mustache +0 -6
  236. package/docs/webapi/scrollPageToTop.mustache +0 -6
  237. package/docs/webapi/scrollTo.mustache +0 -12
  238. package/docs/webapi/see.mustache +0 -11
  239. package/docs/webapi/seeAttributesOnElements.mustache +0 -9
  240. package/docs/webapi/seeCheckboxIsChecked.mustache +0 -10
  241. package/docs/webapi/seeCookie.mustache +0 -8
  242. package/docs/webapi/seeCssPropertiesOnElements.mustache +0 -9
  243. package/docs/webapi/seeCurrentPathEquals.mustache +0 -10
  244. package/docs/webapi/seeCurrentUrlEquals.mustache +0 -11
  245. package/docs/webapi/seeElement.mustache +0 -8
  246. package/docs/webapi/seeElementInDOM.mustache +0 -8
  247. package/docs/webapi/seeInCurrentUrl.mustache +0 -8
  248. package/docs/webapi/seeInField.mustache +0 -12
  249. package/docs/webapi/seeInPopup.mustache +0 -8
  250. package/docs/webapi/seeInSource.mustache +0 -7
  251. package/docs/webapi/seeInTitle.mustache +0 -8
  252. package/docs/webapi/seeNumberOfElements.mustache +0 -11
  253. package/docs/webapi/seeNumberOfVisibleElements.mustache +0 -10
  254. package/docs/webapi/seeTextEquals.mustache +0 -9
  255. package/docs/webapi/seeTitleEquals.mustache +0 -8
  256. package/docs/webapi/seeTraffic.mustache +0 -36
  257. package/docs/webapi/selectOption.mustache +0 -21
  258. package/docs/webapi/setCookie.mustache +0 -16
  259. package/docs/webapi/setGeoLocation.mustache +0 -12
  260. package/docs/webapi/startRecordingTraffic.mustache +0 -8
  261. package/docs/webapi/startRecordingWebSocketMessages.mustache +0 -8
  262. package/docs/webapi/stopRecordingTraffic.mustache +0 -5
  263. package/docs/webapi/stopRecordingWebSocketMessages.mustache +0 -7
  264. package/docs/webapi/switchTo.mustache +0 -9
  265. package/docs/webapi/switchToNextTab.mustache +0 -10
  266. package/docs/webapi/switchToPreviousTab.mustache +0 -10
  267. package/docs/webapi/type.mustache +0 -21
  268. package/docs/webapi/uncheckOption.mustache +0 -13
  269. package/docs/webapi/wait.mustache +0 -8
  270. package/docs/webapi/waitForClickable.mustache +0 -11
  271. package/docs/webapi/waitForCookie.mustache +0 -9
  272. package/docs/webapi/waitForDetached.mustache +0 -10
  273. package/docs/webapi/waitForDisabled.mustache +0 -6
  274. package/docs/webapi/waitForElement.mustache +0 -11
  275. package/docs/webapi/waitForEnabled.mustache +0 -6
  276. package/docs/webapi/waitForFunction.mustache +0 -17
  277. package/docs/webapi/waitForInvisible.mustache +0 -10
  278. package/docs/webapi/waitForNumberOfTabs.mustache +0 -9
  279. package/docs/webapi/waitForText.mustache +0 -13
  280. package/docs/webapi/waitForValue.mustache +0 -10
  281. package/docs/webapi/waitForVisible.mustache +0 -10
  282. package/docs/webapi/waitInUrl.mustache +0 -9
  283. package/docs/webapi/waitNumberOfVisibleElements.mustache +0 -10
  284. package/docs/webapi/waitToHide.mustache +0 -10
  285. package/docs/webapi/waitUrlEquals.mustache +0 -10
  286. package/lib/helper/AI.js +0 -214
  287. package/lib/listener/enhancedGlobalRetry.js +0 -110
  288. package/lib/plugin/enhancedRetryFailedStep.js +0 -99
  289. package/lib/plugin/htmlReporter.js +0 -3648
  290. package/lib/plugin/stepByStepReport.js +0 -427
  291. package/lib/plugin/subtitles.js +0 -89
  292. package/lib/retryCoordinator.js +0 -207
  293. package/typings/promiseBasedTypes.d.ts +0 -9469
  294. package/typings/types.d.ts +0 -11402
package/docs/basics.md ADDED
@@ -0,0 +1,424 @@
1
+ ---
2
+ permalink: /basics
3
+ title: Getting Started
4
+ ---
5
+
6
+ # Getting Started
7
+
8
+ CodeceptJS is a modern end to end testing framework with a special BDD-style syntax. The tests are written as a linear scenario of the user's action on a site.
9
+
10
+ ```js
11
+ Feature('CodeceptJS demo')
12
+
13
+ Scenario('check Welcome page on site', ({ I }) => {
14
+ I.amOnPage('/')
15
+ I.see('Welcome')
16
+ })
17
+ ```
18
+
19
+ Tests are written as **ES modules** using modern JavaScript syntax.
20
+
21
+ Each test is described inside a `Scenario` function with the `I` object passed into it.
22
+ The `I` object is an **actor**, an abstraction for a testing user. The `I` is a proxy object for currently enabled **Helpers**.
23
+
24
+ ## How It Works
25
+
26
+ ### Command Delegation to Helpers
27
+
28
+ **CodeceptJS delegates all test commands to helper backends.** Tests written with the `I` object (the actor) don't directly execute actions. Instead, CodeceptJS routes them through configurable helpers:
29
+
30
+ - **Playwright** - Chromium, Firefox, WebKit automation
31
+ - **WebDriver** - Native browser automation via WebDriver Protocol
32
+ - **Appium** - Mobile testing on iOS/Android
33
+ - **Puppeteer** - Chromium automation via DevTools Protocol
34
+
35
+ All helpers share the same API, so it's easy to switch backends. However, due to backend differences and limitations, they aren't guaranteed to be compatible with each other. For example, you can set request headers in Playwright or Puppeteer, but not in WebDriver.
36
+
37
+ > **Pick one helper to define how your tests execute.** If requirements change, it's straightforward to migrate to another.
38
+
39
+
40
+ ### Promise Chain & Async/Await
41
+
42
+ Tests appear synchronous but **all actions are wrapped in promises and chained together** in a global promise chain. This means:
43
+
44
+ - **You usually don't need `await` for regular actions** - commands are automatically queued
45
+ - Each `I.*` command is appended to the promise chain
46
+ - Setup, teardown, and all test steps execute in sequence
47
+
48
+ ```js
49
+ // These execute in order WITHOUT await
50
+ I.amOnPage('/')
51
+ I.click('Login')
52
+ I.see('Welcome')
53
+ ```
54
+
55
+ Behind the scenes, this is equivalent to:
56
+ ```js
57
+ Promise.resolve()
58
+ .then(() => I.amOnPage('/'))
59
+ .then(() => I.click('Login'))
60
+ .then(() => I.see('Welcome'))
61
+ ```
62
+
63
+ When You DO Need `await`:
64
+
65
+ Use `await` only with **grab** actions (methods that retrieve data from the page):
66
+
67
+ ```js
68
+ Scenario('use data from page', async ({ I }) => {
69
+ I.fillField('email', 'user@example.com')
70
+ I.click('Generate Password')
71
+ // grab actions return data - use await here
72
+ const password = await I.grabTextFrom('#password')
73
+ I.fillField('password', password)
74
+ I.click('Login')
75
+ })
76
+ ```
77
+
78
+ Also **use `await` with imported functions and page object methods**, as they may contain async operations that aren't part of the promise chain (e.g., `await loginPage.login()` if it contains `I.grab` operations inside).
79
+
80
+ > **Rule:** If an action starts with `grab`, or if calling an imported function/page object method, you must `await` it. Regular actions (`I.click()`, `I.fillField()`, `I.see()`) don't need await.
81
+
82
+ ## Writing Tests
83
+
84
+ Tests are written from a user's perspective. There is an actor (represented as `I`) which contains actions taken from helpers. A test is written as a sequence of actions performed by an actor:
85
+
86
+ ```js
87
+ I.amOnPage('/')
88
+ I.click('Login')
89
+ I.see('Please Login', 'h1')
90
+ // ...
91
+ ```
92
+
93
+ A complete test file looks like this:
94
+
95
+ ```js
96
+ // suite declaration, like describe() in other frameworks
97
+ Feature('User Authentication')
98
+
99
+ // before each hook
100
+ Before(({ I }) => {
101
+ I.amOnPage('/')
102
+ })
103
+
104
+ // a test
105
+ Scenario('user can login with valid credentials', ({ I }) => {
106
+ I.click('Login')
107
+ I.fillField('email', 'user@example.com')
108
+ I.fillField('password', 'password123')
109
+ I.click('Sign In')
110
+ I.see('Welcome, User')
111
+ })
112
+
113
+ // after each hook
114
+ After(({ I }) => {
115
+ // ...
116
+ })
117
+ ```
118
+
119
+ > CodeceptJS doesn't allow nested suites or multiple suites in one file.
120
+
121
+ ### Opening a Page
122
+
123
+ A test should usually start by navigating the browser to a website.
124
+
125
+ Start a test by opening a page. Use the `I.amOnPage()` command for this:
126
+
127
+ ```js
128
+ // When "http://site.com" is url in config
129
+ I.amOnPage('/') // -> opens http://site.com/
130
+ I.amOnPage('/about') // -> opens http://site.com/about
131
+ I.amOnPage('https://google.com') // -> https://google.com
132
+ ```
133
+
134
+ When an URL doesn't start with a protocol (http:// or https://) it is considered to be a relative URL and will be appended to the URL which was initially set-up in the config.
135
+
136
+ > It is recommended to use a relative URL and keep the base URL in the config file, so you can easily switch between development, stage, and production environments.
137
+
138
+ ### Locating Elements
139
+
140
+ CodeceptJS supports multiple locating strategies. Most actions accept locators as strings or objects:
141
+
142
+ ```js
143
+ // Basic CSS/XPath
144
+ I.click('.login-btn')
145
+ I.fillField('//input[@type="email"]', 'user@test.com')
146
+
147
+ // Semantic - by text/labels (searches multiple strategies)
148
+ I.click('Login')
149
+ I.fillField('Email', 'user@test.com')
150
+
151
+ // ARIA locators - by role and accessible name (most reliable)
152
+ I.click({ role: 'button', name: 'Login' })
153
+ I.fillField({ role: 'textbox', name: 'Email Address' }, 'user@test.com')
154
+ I.seeElement({ role: 'button', name: 'Submit' })
155
+
156
+ // Accessibility ID or aria-label
157
+ I.click('~login-button')
158
+ I.seeElement({ aria: 'Username' })
159
+
160
+ // Complex locators with locate()
161
+ I.click(locate('button').withText('Save').inside('.modal'))
162
+ I.seeElement(locate({ role: 'button', name: 'Delete' }).inside('.toolbar'))
163
+
164
+ // ARIA + Context - combine role with section to target specific area
165
+ I.click({ role: 'button', name: 'Save' }, '#detail-panel')
166
+ I.fillField({ role: 'textbox', name: 'Title' }, 'New Task', '.modal')
167
+ I.seeElement({ role: 'button', name: 'Delete' }, { css: '.toolbar' })
168
+ I.click({ role: 'button', name: 'Close' }, '.sidebar')
169
+ ```
170
+
171
+ **Best practices:**
172
+
173
+ - **Use ARIA locators** `{ role: 'button', name: '...' }` - resilient to CSS changes and support accessibility
174
+ - **Combine with context** when multiple similar elements exist: `I.click({ role: 'button', name: 'Delete' }, '.toolbar')`
175
+ - **Use semantic CSS classes and IDs** when available (e.g., `.btn-save`, `#login-form`); avoid style-based names like `.bg-green`
176
+ - **Use `locate()` function** for complex queries: `locate(selector).withText(...).inside(...)`
177
+
178
+ > [▶ Learn more about using locators in CodeceptJS](/locators).
179
+
180
+ ### Clicking Elements
181
+
182
+ Use the locator strategies from [Locating Elements](#locating-elements) section to click any element:
183
+
184
+ ```js
185
+ I.click('Login') // by text
186
+ I.click({ role: 'button', name: 'Save' }) // by ARIA role
187
+ I.click('#signup') // by ID
188
+ I.click('Delete', '.toolbar') // with context
189
+ ```
190
+
191
+ | | | | |
192
+ |---|---|---|---|
193
+ | [click](/web-api#iclick) | [forceClick](/web-api#iforcecclick) | [doubleClick](/web-api#idoubleclick) | [rightClick](/web-api#irightclick) |
194
+ | [forceRightClick](/web-api#iforcerightclick) | [moveCursorTo](/web-api#imovecursorto) | [dragAndDrop](/web-api#idraganddrop) | [dragSlider](/web-api#idragslider) |
195
+
196
+ Use **forceClick** when standard click fails (e.g., hidden elements, animations). Use **rightClick** for context menus, **doubleClick** for multi-select.
197
+
198
+ ### Interacting with Forms
199
+
200
+ Use form methods to interact with inputs, selects, checkboxes, and other form elements. Fields can be located by label, name, CSS, XPath, or aria-label:
201
+
202
+ ```js
203
+ // Fill fields - by label, name, CSS, or aria-label
204
+ I.fillField('Email', 'user@test.com')
205
+ I.fillField('My Address', 'Home Sweet Home') // matches aria-label or aria-labelledby
206
+ I.fillField('LoginForm[username]', 'davert') // by field name attribute
207
+ I.fillField('Password', secret('123456')) // use secret() for sensitive data
208
+
209
+ // Use context (3rd parameter) to narrow search to specific form
210
+ I.fillField('Email', 'user@test.com', '#login-form')
211
+ I.fillField('Email', 'admin@test.com', '#registration-form')
212
+
213
+ // Append or clear
214
+ I.appendField('Comments', ' — updated')
215
+ I.appendField('Message', ' P.S. Thank you!', '.contact-form') // with context
216
+ I.clearField('#search-input')
217
+
218
+ // Type into focused field - use when fillField doesn't trigger JS events
219
+ I.click('Card Number')
220
+ I.type('4111111111111111', 100) // optional delay in ms between keystrokes
221
+
222
+ // Selects - pass array for multi-select
223
+ I.selectOption('Role', 'Admin')
224
+ I.selectOption('Role', 'User', '.user-form') // with context
225
+ I.selectOption('Tags', ['Important', 'Urgent'])
226
+
227
+ // Checkboxes and radios - supports context
228
+ I.checkOption('I Agree to Terms and Conditions')
229
+ I.checkOption('Remember me', '#login-form') // with context
230
+ I.uncheckOption('Subscribe')
231
+ ```
232
+
233
+ | | | | |
234
+ |---|---|---|---|
235
+ | [fillField](/web-api#ifillfield) | [clearField](/web-api#iclearfield) | [appendField](/web-api#iappendfield) | [type](/web-api#itype) |
236
+ | [selectOption](/web-api#iselectoption) | [checkOption](/web-api#icheckoption) | [uncheckOption](/web-api#iuncheckoption) | [focus](/web-api#ifocus) |
237
+ | [blur](/web-api#iblur) | | | |
238
+
239
+ > Use `secret()` for sensitive data: `I.fillField('password', secret('123456'))` - [won't expose in logs](/secrets/).
240
+ >
241
+
242
+ > [selectOption](/web-api#iselectoption) works with native `<select>` elements as well as custom components using `role="combobox"` or `role="listbox"`.
243
+
244
+ ### Assertions
245
+
246
+ CodeceptJS provides **built-in browser assertions** instead of generic `expect()` calls. This keeps tests readable and produces clear failure messages without extra assertion libraries.
247
+
248
+ - **`I.see(text)`** - checks that text is visible on the page
249
+ - **`I.seeElement(locator)`** - checks that element exists and is visible in DOM
250
+ - All assertions have a `dontSee` / `dontSee*` counterpart
251
+
252
+ ```js
253
+ // Text visibility
254
+ I.see('Welcome, Miles')
255
+ I.see('Error', '.alert') // with context
256
+ I.dontSee('Loading...')
257
+
258
+ // Element presence
259
+ I.seeElement({ role: 'button', name: 'Submit' })
260
+ I.seeElement('.success-message', '#checkout') // with context
261
+ I.dontSeeElement('.error')
262
+ I.seeElementInDOM('#hidden-input') // in DOM but may be invisible
263
+
264
+ // URL, title, fields
265
+ I.seeInCurrentUrl('/dashboard')
266
+ I.seeInTitle('My App')
267
+ I.seeInField('Email', 'miles@davis.com')
268
+ I.seeCheckboxIsChecked('Accept Terms')
269
+ I.seeCookie('session')
270
+ I.seeNumberOfElements('.item', 5)
271
+ ```
272
+
273
+ | | | | |
274
+ |---|---|---|---|
275
+ | [see](/web-api#isee) | [seeElement](/web-api#iseeelement) | [seeElementInDOM](/web-api#iseeelementindom) | [seeInField](/web-api#iseeinfield) |
276
+ | [dontSee](/web-api#idontsee) | [dontSeeElement](/web-api#idontseelement) | [dontSeeElementInDOM](/web-api#idontseelementindom) | [dontSeeInField](/web-api#idontseeinfield) |
277
+ | [seeInCurrentUrl](/web-api#seeinCurrentUrl) | [seeInTitle](/web-api#seeinTitle) | [seeCheckboxIsChecked](/web-api#iseecheckboxischecked) | [seeCookie](/web-api#iseecookie) |
278
+ | [seeNumberOfElements](/web-api#iseenumberofelements) | [seeNumberOfVisibleElements](/web-api#iseenumberofvisibleelements) | [seeTextEquals](/web-api#iseetextequals) | [seeAttributesOnElements](/web-api#iseeattributesonelements) |
279
+
280
+ For custom assertions use `grab*` methods to retrieve data, then assert with any library
281
+
282
+ ```js
283
+ const title = await I.grabTitle();
284
+ expect(title).toEqual('My App')`
285
+ ```
286
+
287
+ ### Fetching Content from Page
288
+
289
+ **Grabbers retrieve data from the page** for use in subsequent steps. They are the equivalent of Playwright's `textContent()`, Cypress's `cy.get().invoke()`, or WebDriver's `getText()` — but integrated into the CodeceptJS promise chain.
290
+
291
+ **Grabbers always require `await`** since they return data out of the known promise chain.
292
+
293
+ ```js
294
+ const title = await I.grabTitle()
295
+ const text = await I.grabTextFrom('.user-name')
296
+ const val = await I.grabValueFrom('#email-input')
297
+ const href = await I.grabAttributeFrom('a.logo', 'href')
298
+ const count = await I.grabNumberOfVisibleElements('.item')
299
+ ```
300
+
301
+ In complex scenarios, grabbers are used to extract data from page and pass it to next steps.
302
+
303
+ ```js
304
+ Scenario('login with generated password', async ({ I }) => {
305
+ I.click('Generate Password')
306
+ const password = await I.grabTextFrom('#generated-password')
307
+ I.fillField('Password', password)
308
+ I.click('Sign In')
309
+ I.see('Welcome')
310
+ })
311
+ ```
312
+
313
+ | | | | |
314
+ |---|---|---|---|
315
+ | [grabTextFrom](/web-api#igrabtextfrom) | [grabTextFromAll](/web-api#igrabtextfromall) | [grabValueFrom](/web-api#igrabvaluefrom) | [grabValueFromAll](/web-api#igrabvaluefromall) |
316
+ | [grabHTMLFrom](/web-api#igrabhtmlfrom) | [grabAttributeFrom](/web-api#igrabattributefrom) | [grabAttributeFromAll](/web-api#igrabattributefromall) | [grabNumberOfVisibleElements](/web-api#igrabnumberofvisibleelements) |
317
+ | [grabCurrentUrl](/web-api#igrabcurrenturl) | [grabTitle](/web-api#igrabtitle) | [grabCookie](/web-api#igrabcookie) | [grabSource](/web-api#igrabsource) |
318
+ | [grabWebElement](/web-api#igrabwebelement) | [grabWebElements](/web-api#igrabwebelements) | [grabElementBoundingRect](/web-api#igrabelementboundingrect) | [grabCssPropertyFrom](/web-api#igrabcsspropertyfrom) |
319
+
320
+ ### Waiting
321
+
322
+ **CodeceptJS automatically waits** for elements before clicking, filling, and most other interactions — so explicit waits are rarely needed. Failed steps are also [automatically retried](/basics#auto-retry).
323
+
324
+ Use `wait*` methods when you need to explicitly wait for a UI change, such as a modal appearing, a spinner hiding, or a value updating:
325
+
326
+ ```js
327
+ I.waitForVisible('.modal') // wait for modal to appear
328
+ I.waitForInvisible('.spinner') // wait for spinner to hide
329
+ I.waitForText('Success', 5, '.alert') // wait for text in element (5s timeout)
330
+ I.waitForEnabled('#submit-btn') // wait for button to become enabled
331
+ I.waitForElement('.results li', 10) // wait for results to load
332
+
333
+ I.wait(2) // explicit pause in seconds (last resort)
334
+ ```
335
+
336
+ Example usage inside scenario:
337
+
338
+ ```js
339
+ Scenario('submit and wait for confirmation', ({ I }) => {
340
+ I.click('Submit Order')
341
+ I.waitForVisible('.order-confirmation', 10)
342
+ I.see('Order placed successfully', '.order-confirmation')
343
+ })
344
+ ```
345
+
346
+ | | | | |
347
+ |---|---|---|---|
348
+ | [waitForVisible](/web-api#iwaitforvisible) | [waitForInvisible](/web-api#iwaitforinvisible) | [waitForElement](/web-api#iwaitforelement) | [waitForDetached](/web-api#iwaitfordetached) |
349
+ | [waitForText](/web-api#iwaitfortext) | [waitForValue](/web-api#iwaitforvalue) | [waitForClickable](/web-api#iwaitforclickable) | [waitForEnabled](/web-api#iwaitforenabled) |
350
+ | [waitForDisabled](/web-api#iwaitfordisabled) | [waitForFunction](/web-api#iwaitforfunction) | [waitToHide](/web-api#iwaittohide) | [waitInUrl](/web-api#iwaitinurl) |
351
+ | [waitUrlEquals](/web-api#iwaitUrlEquals) | [waitNumberOfVisibleElements](/web-api#iwaitnumberofvisibleelements) | [wait](/web-api#iwait) | |
352
+
353
+ ## Running Tests
354
+
355
+
356
+ ```bash
357
+ npx codeceptjs run # run all tests
358
+ npx codeceptjs run tests/login_test.js # run a single file
359
+ npx codeceptjs run --grep "checkout" # run tests matching name pattern
360
+ npx codeceptjs run --grep "@smoke" # run tests by tag
361
+ ```
362
+
363
+ Run tests in parallel using [NodeJS workers](https://nodejs.org/api/worker_threads.html). Tests are split by scenarios, results aggregated in the main process:
364
+
365
+ ```bash
366
+ npx codeceptjs run-workers 3 # run with 3 parallel workers
367
+ ```
368
+
369
+
370
+ ### Output Verbosity
371
+
372
+ ```bash
373
+ npx codeceptjs run --steps # print each step
374
+ npx codeceptjs run --debug # print steps + additional debug info
375
+ npx codeceptjs run --verbose # print everything including promises
376
+ ```
377
+
378
+ It is recommended to always launch tests in `--debug` mode when developing tests.
379
+
380
+ ### Headless / Headed Mode
381
+
382
+ By default tests run headless (no browser window). To open a browser during test execution set `show: true` in helper config, or use `@codeceptjs/configure`:
383
+
384
+ ```js
385
+ import { setHeadlessWhen } from '@codeceptjs/configure'
386
+
387
+ setHeadlessWhen(process.env.CI) // headless only on CI, show browser locally
388
+ ```
389
+
390
+ For a single run without editing config, use the `browser` plugin:
391
+
392
+ ```sh
393
+ npx codeceptjs run -p browser:show # force visible browser
394
+ npx codeceptjs run -p browser:hide # force headless
395
+ ```
396
+
397
+ See [Plugin Arguments](/commands#plugin-arguments).
398
+
399
+
400
+ ## Configuration
401
+
402
+ Configuration is set in `codecept.conf.js`. The two most important settings are the **helper** (which browser engine to use) and the **base URL** of your application:
403
+
404
+ ```js
405
+ export const config = {
406
+ helpers: {
407
+ Playwright: {
408
+ url: 'http://localhost:3000', // base URL for I.amOnPage('/')
409
+ show: !process.env.CI, // show browser locally, headless on CI
410
+ browser: 'chromium',
411
+ },
412
+ },
413
+ tests: './**/*_test.js',
414
+ output: './output',
415
+ }
416
+ ```
417
+
418
+ Use `-c` to switch between config files:
419
+
420
+ ```bash
421
+ npx codeceptjs run -c codecept.ci.conf.js
422
+ ```
423
+
424
+ > ▶ See complete [configuration reference](/configuration).