codeceptjs 4.0.1-beta.9 → 4.0.1

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 (328) hide show
  1. package/README.md +39 -28
  2. package/bin/codecept.js +17 -4
  3. package/bin/codeceptq.js +49 -0
  4. package/bin/mcp-server.js +1189 -0
  5. package/docs/advanced.md +201 -0
  6. package/docs/agents.md +181 -0
  7. package/docs/ai.md +489 -0
  8. package/docs/aitrace.md +266 -0
  9. package/docs/api.md +332 -0
  10. package/docs/architecture.md +235 -0
  11. package/docs/assertions.md +415 -0
  12. package/docs/auth.md +318 -0
  13. package/docs/basics.md +424 -0
  14. package/docs/bdd.md +539 -0
  15. package/docs/best.md +240 -0
  16. package/docs/bootstrap.md +132 -0
  17. package/docs/commands.md +352 -0
  18. package/docs/community-helpers.md +63 -0
  19. package/docs/configuration.md +185 -0
  20. package/docs/continuous-integration.md +431 -0
  21. package/docs/custom-helpers.md +297 -0
  22. package/docs/data.md +448 -0
  23. package/docs/debugging.md +332 -0
  24. package/docs/detox.md +235 -0
  25. package/docs/docker.md +107 -0
  26. package/docs/effects.md +179 -0
  27. package/docs/element-based-testing.md +295 -0
  28. package/docs/element-selection.md +125 -0
  29. package/docs/els.md +328 -0
  30. package/docs/environment-variables.md +131 -0
  31. package/docs/examples.md +160 -0
  32. package/docs/heal.md +213 -0
  33. package/docs/helpers/ApiDataFactory.md +267 -0
  34. package/docs/helpers/Appium.md +1419 -0
  35. package/docs/helpers/Detox.md +665 -0
  36. package/docs/helpers/ExpectHelper.md +275 -0
  37. package/docs/helpers/FileSystem.md +152 -0
  38. package/docs/helpers/GraphQL.md +152 -0
  39. package/docs/helpers/GraphQLDataFactory.md +226 -0
  40. package/docs/helpers/JSONResponse.md +255 -0
  41. package/docs/helpers/MockRequest.md +377 -0
  42. package/docs/helpers/Playwright.md +2970 -0
  43. package/docs/helpers/Puppeteer-firefox.md +86 -0
  44. package/docs/helpers/Puppeteer.md +2583 -0
  45. package/docs/helpers/REST.md +289 -0
  46. package/docs/helpers/WebDriver.md +2639 -0
  47. package/docs/hooks.md +148 -0
  48. package/docs/index.md +111 -0
  49. package/docs/installation.md +121 -0
  50. package/docs/internal-test-server.md +89 -0
  51. package/docs/locators.md +355 -0
  52. package/docs/mcp.md +485 -0
  53. package/docs/migrate-from-cypress.md +98 -0
  54. package/docs/migrate-from-java.md +108 -0
  55. package/docs/migrate-from-protractor.md +101 -0
  56. package/docs/migrate-from-testcafe.md +99 -0
  57. package/docs/migration-4.md +745 -0
  58. package/docs/mobile.md +338 -0
  59. package/docs/pageobjects.md +399 -0
  60. package/docs/parallel.md +187 -0
  61. package/docs/playwright.md +714 -0
  62. package/docs/plugins/aiTrace.md +49 -0
  63. package/docs/plugins/analyze.md +66 -0
  64. package/docs/plugins/auth.md +241 -0
  65. package/docs/plugins/autoDelay.md +48 -0
  66. package/docs/plugins/browser.md +41 -0
  67. package/docs/plugins/coverage.md +39 -0
  68. package/docs/plugins/customLocator.md +119 -0
  69. package/docs/plugins/customReporter.md +16 -0
  70. package/docs/plugins/expose.md +75 -0
  71. package/docs/plugins/heal.md +44 -0
  72. package/docs/plugins/junitReporter.md +51 -0
  73. package/docs/plugins/pageInfo.md +34 -0
  74. package/docs/plugins/pause.md +43 -0
  75. package/docs/plugins/pauseOnFail.md +18 -0
  76. package/docs/plugins/retryFailedStep.md +75 -0
  77. package/docs/plugins/screencast.md +55 -0
  78. package/docs/plugins/screenshot.md +58 -0
  79. package/docs/plugins/screenshotOnFail.md +18 -0
  80. package/docs/plugins/stepTimeout.md +65 -0
  81. package/docs/plugins.md +87 -0
  82. package/docs/puppeteer.md +314 -0
  83. package/docs/quickstart.md +120 -0
  84. package/docs/reports.md +195 -0
  85. package/docs/retry.md +311 -0
  86. package/docs/secrets.md +150 -0
  87. package/docs/sessions.md +80 -0
  88. package/docs/shadow.md +68 -0
  89. package/docs/store.md +94 -0
  90. package/docs/test-structure.md +275 -0
  91. package/docs/timeouts.md +183 -0
  92. package/docs/translation.md +247 -0
  93. package/docs/tutorial.md +323 -0
  94. package/docs/typescript.md +159 -0
  95. package/docs/web-element.md +251 -0
  96. package/docs/webdriver.md +641 -0
  97. package/docs/within.md +55 -0
  98. package/lib/actor.js +1 -36
  99. package/lib/ai.js +3 -2
  100. package/lib/aria.js +260 -0
  101. package/lib/assertions.js +18 -0
  102. package/lib/codecept.js +34 -25
  103. package/lib/command/check.js +2 -1
  104. package/lib/command/definitions.js +14 -10
  105. package/lib/command/dryRun.js +24 -5
  106. package/lib/command/generate.js +3 -1
  107. package/lib/command/gherkin/snippets.js +5 -4
  108. package/lib/command/init.js +249 -270
  109. package/lib/command/list.js +150 -10
  110. package/lib/command/query.js +218 -0
  111. package/lib/command/run-multiple.js +3 -2
  112. package/lib/command/run-workers.js +14 -16
  113. package/lib/command/run.js +3 -17
  114. package/lib/command/utils.js +14 -0
  115. package/lib/command/workers/runTests.js +117 -9
  116. package/lib/config.js +98 -19
  117. package/lib/container.js +188 -19
  118. package/lib/effects.js +17 -0
  119. package/lib/element/WebElement.js +246 -2
  120. package/lib/els.js +12 -6
  121. package/lib/globals.js +32 -19
  122. package/lib/heal.js +7 -4
  123. package/lib/helper/ApiDataFactory.js +2 -1
  124. package/lib/helper/Appium.js +8 -8
  125. package/lib/helper/FileSystem.js +3 -2
  126. package/lib/helper/GraphQLDataFactory.js +2 -1
  127. package/lib/helper/Playwright.js +367 -516
  128. package/lib/helper/Puppeteer.js +343 -197
  129. package/lib/helper/WebDriver.js +324 -111
  130. package/lib/helper/errors/ElementNotFound.js +5 -2
  131. package/lib/helper/errors/MultipleElementsFound.js +52 -0
  132. package/lib/helper/errors/NonFocusedType.js +8 -0
  133. package/lib/helper/extras/Download.js +45 -0
  134. package/lib/helper/extras/PlaywrightLocator.js +7 -107
  135. package/lib/helper/extras/elementSelection.js +58 -0
  136. package/lib/helper/extras/focusCheck.js +43 -0
  137. package/lib/helper/extras/richTextEditor.js +178 -0
  138. package/lib/helper/scripts/dropFile.js +11 -0
  139. package/lib/history.js +3 -2
  140. package/lib/html.js +103 -16
  141. package/lib/index.js +9 -1
  142. package/lib/listener/config.js +6 -4
  143. package/lib/listener/emptyRun.js +2 -1
  144. package/lib/listener/globalRetry.js +32 -6
  145. package/lib/listener/helpers.js +6 -15
  146. package/lib/listener/mocha.js +2 -1
  147. package/lib/listener/pageobjects.js +43 -0
  148. package/lib/listener/result.js +3 -2
  149. package/lib/locator.js +158 -16
  150. package/lib/mocha/cli.js +19 -1
  151. package/lib/mocha/factory.js +13 -28
  152. package/lib/mocha/inject.js +1 -1
  153. package/lib/mocha/scenarioConfig.js +2 -1
  154. package/lib/mocha/test.js +4 -2
  155. package/lib/mocha/ui.js +5 -6
  156. package/lib/output.js +2 -2
  157. package/lib/parser.js +2 -2
  158. package/lib/pause.js +38 -4
  159. package/lib/plugin/aiTrace.js +457 -0
  160. package/lib/plugin/analyze.js +9 -9
  161. package/lib/plugin/auth.js +5 -4
  162. package/lib/plugin/browser.js +77 -0
  163. package/lib/plugin/expose.js +159 -0
  164. package/lib/plugin/heal.js +47 -3
  165. package/lib/plugin/junitReporter.js +303 -0
  166. package/lib/plugin/pageInfo.js +54 -52
  167. package/lib/plugin/pause.js +131 -0
  168. package/lib/plugin/pauseOnFail.js +11 -33
  169. package/lib/plugin/retryFailedStep.js +43 -32
  170. package/lib/plugin/screencast.js +289 -0
  171. package/lib/plugin/screenshot.js +558 -0
  172. package/lib/plugin/screenshotOnFail.js +9 -170
  173. package/lib/plugin/stepTimeout.js +3 -2
  174. package/lib/recorder.js +1 -1
  175. package/lib/rerun.js +2 -1
  176. package/lib/result.js +2 -1
  177. package/lib/step/base.js +23 -9
  178. package/lib/step/comment.js +2 -2
  179. package/lib/step/config.js +15 -2
  180. package/lib/step/helper.js +4 -4
  181. package/lib/step/meta.js +3 -3
  182. package/lib/step/record.js +12 -4
  183. package/lib/store.js +72 -3
  184. package/lib/translation.js +2 -1
  185. package/lib/utils/loaderCheck.js +41 -3
  186. package/lib/utils/mask_data.js +2 -1
  187. package/lib/utils/pluginParser.js +151 -0
  188. package/lib/utils/trace.js +297 -0
  189. package/lib/utils/typescript.js +261 -49
  190. package/lib/utils.js +77 -3
  191. package/lib/workers.js +123 -17
  192. package/package.json +48 -43
  193. package/typings/index.d.ts +120 -9
  194. package/typings/promiseBasedTypes.d.ts +3243 -6057
  195. package/typings/types.d.ts +3541 -6506
  196. package/docs/webapi/amOnPage.mustache +0 -11
  197. package/docs/webapi/appendField.mustache +0 -11
  198. package/docs/webapi/attachFile.mustache +0 -12
  199. package/docs/webapi/blur.mustache +0 -18
  200. package/docs/webapi/checkOption.mustache +0 -13
  201. package/docs/webapi/clearCookie.mustache +0 -9
  202. package/docs/webapi/clearField.mustache +0 -9
  203. package/docs/webapi/click.mustache +0 -29
  204. package/docs/webapi/clickLink.mustache +0 -8
  205. package/docs/webapi/closeCurrentTab.mustache +0 -7
  206. package/docs/webapi/closeOtherTabs.mustache +0 -8
  207. package/docs/webapi/dontSee.mustache +0 -11
  208. package/docs/webapi/dontSeeCheckboxIsChecked.mustache +0 -10
  209. package/docs/webapi/dontSeeCookie.mustache +0 -8
  210. package/docs/webapi/dontSeeCurrentUrlEquals.mustache +0 -10
  211. package/docs/webapi/dontSeeElement.mustache +0 -8
  212. package/docs/webapi/dontSeeElementInDOM.mustache +0 -8
  213. package/docs/webapi/dontSeeInCurrentUrl.mustache +0 -4
  214. package/docs/webapi/dontSeeInField.mustache +0 -11
  215. package/docs/webapi/dontSeeInSource.mustache +0 -8
  216. package/docs/webapi/dontSeeInTitle.mustache +0 -8
  217. package/docs/webapi/dontSeeTraffic.mustache +0 -13
  218. package/docs/webapi/doubleClick.mustache +0 -13
  219. package/docs/webapi/downloadFile.mustache +0 -12
  220. package/docs/webapi/dragAndDrop.mustache +0 -9
  221. package/docs/webapi/dragSlider.mustache +0 -11
  222. package/docs/webapi/executeAsyncScript.mustache +0 -24
  223. package/docs/webapi/executeScript.mustache +0 -26
  224. package/docs/webapi/fillField.mustache +0 -16
  225. package/docs/webapi/flushNetworkTraffics.mustache +0 -5
  226. package/docs/webapi/focus.mustache +0 -13
  227. package/docs/webapi/forceClick.mustache +0 -28
  228. package/docs/webapi/forceRightClick.mustache +0 -18
  229. package/docs/webapi/grabAllWindowHandles.mustache +0 -7
  230. package/docs/webapi/grabAttributeFrom.mustache +0 -10
  231. package/docs/webapi/grabAttributeFromAll.mustache +0 -9
  232. package/docs/webapi/grabBrowserLogs.mustache +0 -9
  233. package/docs/webapi/grabCookie.mustache +0 -11
  234. package/docs/webapi/grabCssPropertyFrom.mustache +0 -11
  235. package/docs/webapi/grabCssPropertyFromAll.mustache +0 -10
  236. package/docs/webapi/grabCurrentUrl.mustache +0 -9
  237. package/docs/webapi/grabCurrentWindowHandle.mustache +0 -6
  238. package/docs/webapi/grabDataFromPerformanceTiming.mustache +0 -20
  239. package/docs/webapi/grabElementBoundingRect.mustache +0 -20
  240. package/docs/webapi/grabGeoLocation.mustache +0 -8
  241. package/docs/webapi/grabHTMLFrom.mustache +0 -10
  242. package/docs/webapi/grabHTMLFromAll.mustache +0 -9
  243. package/docs/webapi/grabNumberOfOpenTabs.mustache +0 -8
  244. package/docs/webapi/grabNumberOfVisibleElements.mustache +0 -9
  245. package/docs/webapi/grabPageScrollPosition.mustache +0 -8
  246. package/docs/webapi/grabPopupText.mustache +0 -5
  247. package/docs/webapi/grabRecordedNetworkTraffics.mustache +0 -10
  248. package/docs/webapi/grabSource.mustache +0 -8
  249. package/docs/webapi/grabTextFrom.mustache +0 -10
  250. package/docs/webapi/grabTextFromAll.mustache +0 -9
  251. package/docs/webapi/grabTitle.mustache +0 -8
  252. package/docs/webapi/grabValueFrom.mustache +0 -9
  253. package/docs/webapi/grabValueFromAll.mustache +0 -8
  254. package/docs/webapi/grabWebElement.mustache +0 -9
  255. package/docs/webapi/grabWebElements.mustache +0 -9
  256. package/docs/webapi/moveCursorTo.mustache +0 -12
  257. package/docs/webapi/openNewTab.mustache +0 -7
  258. package/docs/webapi/pressKey.mustache +0 -12
  259. package/docs/webapi/pressKeyDown.mustache +0 -12
  260. package/docs/webapi/pressKeyUp.mustache +0 -12
  261. package/docs/webapi/pressKeyWithKeyNormalization.mustache +0 -60
  262. package/docs/webapi/refreshPage.mustache +0 -6
  263. package/docs/webapi/resizeWindow.mustache +0 -6
  264. package/docs/webapi/rightClick.mustache +0 -14
  265. package/docs/webapi/saveElementScreenshot.mustache +0 -10
  266. package/docs/webapi/saveScreenshot.mustache +0 -12
  267. package/docs/webapi/say.mustache +0 -10
  268. package/docs/webapi/scrollIntoView.mustache +0 -11
  269. package/docs/webapi/scrollPageToBottom.mustache +0 -6
  270. package/docs/webapi/scrollPageToTop.mustache +0 -6
  271. package/docs/webapi/scrollTo.mustache +0 -12
  272. package/docs/webapi/see.mustache +0 -11
  273. package/docs/webapi/seeAttributesOnElements.mustache +0 -9
  274. package/docs/webapi/seeCheckboxIsChecked.mustache +0 -10
  275. package/docs/webapi/seeCookie.mustache +0 -8
  276. package/docs/webapi/seeCssPropertiesOnElements.mustache +0 -9
  277. package/docs/webapi/seeCurrentUrlEquals.mustache +0 -11
  278. package/docs/webapi/seeElement.mustache +0 -8
  279. package/docs/webapi/seeElementInDOM.mustache +0 -8
  280. package/docs/webapi/seeInCurrentUrl.mustache +0 -8
  281. package/docs/webapi/seeInField.mustache +0 -12
  282. package/docs/webapi/seeInPopup.mustache +0 -8
  283. package/docs/webapi/seeInSource.mustache +0 -7
  284. package/docs/webapi/seeInTitle.mustache +0 -8
  285. package/docs/webapi/seeNumberOfElements.mustache +0 -11
  286. package/docs/webapi/seeNumberOfVisibleElements.mustache +0 -10
  287. package/docs/webapi/seeTextEquals.mustache +0 -9
  288. package/docs/webapi/seeTitleEquals.mustache +0 -8
  289. package/docs/webapi/seeTraffic.mustache +0 -36
  290. package/docs/webapi/selectOption.mustache +0 -21
  291. package/docs/webapi/setCookie.mustache +0 -16
  292. package/docs/webapi/setGeoLocation.mustache +0 -12
  293. package/docs/webapi/startRecordingTraffic.mustache +0 -8
  294. package/docs/webapi/startRecordingWebSocketMessages.mustache +0 -8
  295. package/docs/webapi/stopRecordingTraffic.mustache +0 -5
  296. package/docs/webapi/stopRecordingWebSocketMessages.mustache +0 -7
  297. package/docs/webapi/switchTo.mustache +0 -9
  298. package/docs/webapi/switchToNextTab.mustache +0 -10
  299. package/docs/webapi/switchToPreviousTab.mustache +0 -10
  300. package/docs/webapi/type.mustache +0 -21
  301. package/docs/webapi/uncheckOption.mustache +0 -13
  302. package/docs/webapi/wait.mustache +0 -8
  303. package/docs/webapi/waitForClickable.mustache +0 -11
  304. package/docs/webapi/waitForCookie.mustache +0 -9
  305. package/docs/webapi/waitForDetached.mustache +0 -10
  306. package/docs/webapi/waitForDisabled.mustache +0 -6
  307. package/docs/webapi/waitForElement.mustache +0 -11
  308. package/docs/webapi/waitForEnabled.mustache +0 -6
  309. package/docs/webapi/waitForFunction.mustache +0 -17
  310. package/docs/webapi/waitForInvisible.mustache +0 -10
  311. package/docs/webapi/waitForNumberOfTabs.mustache +0 -9
  312. package/docs/webapi/waitForText.mustache +0 -13
  313. package/docs/webapi/waitForValue.mustache +0 -10
  314. package/docs/webapi/waitForVisible.mustache +0 -10
  315. package/docs/webapi/waitInUrl.mustache +0 -9
  316. package/docs/webapi/waitNumberOfVisibleElements.mustache +0 -10
  317. package/docs/webapi/waitToHide.mustache +0 -10
  318. package/docs/webapi/waitUrlEquals.mustache +0 -10
  319. package/lib/helper/AI.js +0 -214
  320. package/lib/helper/Mochawesome.js +0 -96
  321. package/lib/helper/extras/PlaywrightReactVueLocator.js +0 -52
  322. package/lib/helper/extras/React.js +0 -65
  323. package/lib/listener/enhancedGlobalRetry.js +0 -110
  324. package/lib/plugin/enhancedRetryFailedStep.js +0 -99
  325. package/lib/plugin/htmlReporter.js +0 -3648
  326. package/lib/plugin/stepByStepReport.js +0 -427
  327. package/lib/plugin/subtitles.js +0 -89
  328. package/lib/retryCoordinator.js +0 -207
@@ -0,0 +1,641 @@
1
+ ---
2
+ permalink: /webdriver
3
+ title: Testing with WebDriver
4
+ ---
5
+
6
+ # Testing with WebDriver
7
+
8
+ How does your client, manager, or tester, or any other non-technical person, know your web application is working? By opening the browser, accessing a site, clicking on links, filling in the forms, and actually seeing the content on a web page.
9
+
10
+ End-to-End tests can cover standard but complex scenarios from a user's perspective. With e2e tests you can be confident that users, following all defined scenarios, won't get errors. We check **functionality of application and a user interface** (UI) as well.
11
+
12
+ We use [webdriverio](https://webdriver.io) library to run tests over WebDriver. To proceed you need to have [CodeceptJS installed](/quickstart#using-selenium-webdriver) and `WebDriver` helper selected.
13
+
14
+ 🛩️ No Selenium Server, ChromeDriver, GeckoDriver, or driver services to install or start. Since WebdriverIO 9, driver management is fully automatic — WebdriverIO downloads and starts the matching driver for you. Read more [here](https://webdriver.io/blog/2023/07/31/driver-management/).
15
+
16
+ WebDriver Helper only starts a driver automatically when no connection information (like `host` or `port`) is specified. If you have a custom grid, use a cloud service, or prefer to run your own driver, set those connection options and that endpoint is used instead.
17
+
18
+ Example:
19
+
20
+ ```js
21
+ {
22
+ helpers: {
23
+ WebDriver : {
24
+ smartWait: 5000,
25
+ browser: "chrome",
26
+ restart: false,
27
+ windowSize: "maximize",
28
+ timeouts: {
29
+ "script": 60000,
30
+ "page load": 10000
31
+ }
32
+ }
33
+ }
34
+ }
35
+ ```
36
+
37
+ Testing Chrome locally is now more convenient than ever. You can define a browser channel, and WebDriver Helper will take care of downloading the specified browser version for you.
38
+ For example:
39
+
40
+ ```js
41
+ {
42
+ helpers: {
43
+ WebDriver : {
44
+ smartWait: 5000,
45
+ browser: "chrome",
46
+ browserVersion: '116.0.5793.0', // or 'stable', 'beta', 'dev' or 'canary'
47
+ restart: false,
48
+ windowSize: "maximize",
49
+ timeouts: {
50
+ "script": 60000,
51
+ "page load": 10000
52
+ }
53
+ }
54
+ }
55
+ }
56
+ ```
57
+
58
+ ## Configuring WebDriver
59
+
60
+ WebDriver can be configured to run browser tests in window, headlessly, on a remote server or in a cloud.
61
+
62
+ > By default, CodeceptJS is already configured to run WebDriver tests locally with Chrome or Firefox. If you just need to start running tests - proceed to the next chapter.
63
+
64
+ Configuration for WebDriver should be provided inside `codecept.conf.(js|ts)` file under `helpers: WebDriver` section:
65
+
66
+ ```js
67
+ helpers: {
68
+ WebDriver: {
69
+ url: 'https://myapp.com',
70
+ browser: 'chrome',
71
+ host: '127.0.0.1',
72
+ port: 4444,
73
+ restart: false,
74
+ windowSize: '1920x1680',
75
+ desiredCapabilities: {
76
+ chromeOptions: {
77
+ args: [ /*"--headless",*/ "--disable-gpu", "--no-sandbox" ]
78
+ }
79
+ }
80
+ },
81
+ }
82
+ ```
83
+
84
+ By default, CodeceptJS runs tests in the same browser window but clears cookies and local storage after each test. This behavior can be changed with these options:
85
+
86
+ ```js
87
+ // change to true to restart browser between tests
88
+ restart: false,
89
+ // don't change browser state and not clear cookies between tests
90
+ keepBrowserState: true,
91
+ keepCookies: true,
92
+ ```
93
+
94
+ > ▶ More config options available on [WebDriver helper reference](/helpers/WebDriver#configuration)
95
+
96
+ ### Headless Mode
97
+
98
+ The bundled `@codeceptjs/configure` toggles headless mode for WebDriver — for chrome/firefox it injects `--headless` into the matching capability args automatically:
99
+
100
+ ```js
101
+ // inside codecept.conf.js
102
+ import { setHeadlessWhen, setWindowSize } from '@codeceptjs/configure'
103
+
104
+ setHeadlessWhen(process.env.HEADLESS) // enables headless mode when HEADLESS env var is set
105
+ setWindowSize(1280, 720)
106
+ ```
107
+
108
+ For one-off runs without editing config, the [`browser` plugin](/commands#browser-control) does the same from the CLI:
109
+
110
+ ```sh
111
+ npx codeceptjs run -p browser:hide # force headless
112
+ npx codeceptjs run -p browser:hide:windowSize=1280x720 # combined
113
+ ```
114
+
115
+ Alternatively, you can enable headless mode manually via desired capabilities.
116
+
117
+ ### Desired Capabilities
118
+
119
+ Additional configuration can be passed via `desiredCapabilities` option.
120
+ For instance, this is how we can set to **run headless Chrome**:
121
+
122
+ ```js
123
+ desiredCapabilities: {
124
+ chromeOptions: {
125
+ args: [ "--headless", "--disable-gpu", "--window-size=1200,1000", "--no-sandbox" ]
126
+ }
127
+ }
128
+ ```
129
+
130
+ Next popular use case for capabilities is configuring what to do with unhandled alert popups.
131
+
132
+ ```js
133
+ desiredCapabilities: {
134
+ // close all unexpected popups
135
+ unexpectedAlertBehaviour: 'dismiss',
136
+ }
137
+ ```
138
+
139
+ ### Cloud Providers
140
+
141
+ By default, WebdriverIO starts a local driver automatically, so no connection parameters are needed. To run tests via [Cloud Providers](/helpers/WebDriver#cloud-providers) instead, specify `host`, `port`, `protocol`, and `path` parameters pointing to the service. You may also need `user` and `key` parameters to authenticate on the cloud service.
142
+
143
+ There are also [browser and platform specific capabilities](https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities). Services like SauceLabs, BrowserStack or browser vendors can provide their own specific capabilities for more tuning.
144
+
145
+ Here is a sample BrowserStack config for running tests on iOS mobile browser:
146
+
147
+ ```js
148
+ helpers: {
149
+ WebDriver: {
150
+ host: 'hub.browserstack.com',
151
+ path: '/wd/hub',
152
+ url: 'http://WEBSITE:8080/renderer',
153
+ user: 'xx', // credentials
154
+ key: 'xx', // credentials
155
+ browser: 'iphone',
156
+ desiredCapabilities: {
157
+ 'os_version' : '11',
158
+ 'device' : 'iPhone 8', // you can select device
159
+ 'real_mobile' : 'true', // real or emulated
160
+ 'browserstack.local' : 'true',
161
+ 'browserstack.debug' : 'true',
162
+ 'browserstack.networkLogs' : 'true',
163
+ 'browserstack.appium_version' : '1.9.1',
164
+ 'browserstack.user' : 'xx', // credentials
165
+ 'browserstack.key' : 'xx' // credentials
166
+ }
167
+ }
168
+ ```
169
+
170
+
171
+ ## Writing Tests
172
+
173
+ CodeceptJS provides high-level API on top of WebDriver protocol. While most standard implementations focus on dealing with WebElements on page, CodeceptJS is about user scenarios and interactions. That's why you don't have a direct access to web elements inside a test, but it is proved that in majority of cases you don't need it. Tests written from user's perspective are simpler to write, understand, log and debug.
174
+
175
+ > If you come from Java, Python or Ruby don't be afraid of a new syntax. It is more flexible than you think!
176
+
177
+ A typical test case may look like this:
178
+
179
+ ```js
180
+ Feature('login');
181
+
182
+ Scenario('login test', ({ I }) => {
183
+ I.amOnPage('/login');
184
+ I.fillField('Username', 'john');
185
+ I.fillField('Password', '123456');
186
+ I.click('Login');
187
+ I.see('Welcome, John');
188
+ });
189
+ ```
190
+
191
+ An empty test case can be created with `npx codeceptjs gt` command.
192
+
193
+ ```
194
+ npx codeceptjs gt
195
+ ```
196
+
197
+
198
+ ### Actions
199
+
200
+ Tests consist with a scenario of user's action taken on a page. The most widely used ones are:
201
+
202
+ * `amOnPage` - to open a webpage (accepts relative or absolute url)
203
+ * `click` - to locate a button or link and click on it
204
+ * `fillField` - to enter a text inside a field
205
+ * `selectOption`, `checkOption` - to interact with a form
206
+ * `wait*` to wait for some parts of page to be fully rendered (important for testing SPA)
207
+ * `grab*` to get values from page sources
208
+ * `see`, `dontSee` - to check for a text on a page
209
+ * `seeElement`, `dontSeeElement` - to check for elements on a page
210
+
211
+ > ℹ All actions are listed in [WebDriver helper reference](https://codecept.io/helpers/WebDriver/).*
212
+
213
+ All actions which interact with elements **support CSS and XPath locators**. Actions like `click` or `fillField` by locate elements by their name or value on a page:
214
+
215
+ ```js
216
+ // search for link or button
217
+ I.click('Login');
218
+ // locate field by its label
219
+ I.fillField('Name', 'Miles');
220
+ // we can use input name
221
+ I.fillField('user[email]','miles@davis.com');
222
+ ```
223
+
224
+ You can also specify the exact locator type with strict locators:
225
+
226
+ ```js
227
+ I.click({css: 'button.red'});
228
+ I.fillField({name: 'user[email]'},'miles@davis.com');
229
+ I.seeElement({xpath: '//body/header'});
230
+ ```
231
+
232
+ ### Interactive Pause
233
+
234
+ It's easy to start writing a test if you use [interactive pause](/basics#debug). Just open a web page and pause execution.
235
+
236
+ ```js
237
+ Feature('Sample Test');
238
+
239
+ Scenario('open my website', ({ I }) => {
240
+ I.amOnPage('/');
241
+ pause();
242
+ });
243
+ ```
244
+
245
+ This is just enough to run a test, open a browser, and think what to do next to write a test case.
246
+
247
+ When you execute such test with `npx codeceptjs run` command you may see the browser is started
248
+
249
+ ```
250
+ npx codeceptjs run --steps
251
+ ```
252
+
253
+ After a page is opened a full control of a browser is given to a terminal. Type in different commands such as `click`, `see`, `fillField` to write the test. A successful commands will be saved to `./output/cli-history` file and can be copied into a test.
254
+
255
+ > ℹ All actions are listed in [WebDriver helper reference](/helpers/WebDriver).
256
+
257
+ An interactive shell output may look like this:
258
+
259
+ ```
260
+ Interactive shell started
261
+ Use JavaScript syntax to try steps in action
262
+ - Press ENTER to run the next step
263
+ - Press TAB twice to see all available commands
264
+ - Type exit + Enter to exit the interactive shell
265
+ I.fillField('.new-todo', 'Write a test')
266
+ I.pressKey('Enter')
267
+ I.
268
+ Commands have been saved to /home/davert/demos/codeceptjs/output/cli-history
269
+ ```
270
+ After typing in successful commands you can copy them into a test.
271
+
272
+ Here is a test checking basic [todo application](https://todomvc.com/).
273
+
274
+ ```js
275
+ Feature('TodoMVC');
276
+
277
+ Scenario('create todo item', ({ I }) => {
278
+ I.amOnPage('/examples/vue/');
279
+ I.waitForElement('.new-todo');
280
+ I.fillField('.new-todo', 'Write a test')
281
+ I.pressKey('Enter');
282
+ I.see('1 item left', '.todo-count');
283
+ });
284
+ ```
285
+
286
+ > [▶ Working example of CodeceptJS WebDriver tests](https://github.com/DavertMik/codeceptjs-webdriver-example) for TodoMVC application.
287
+
288
+ WebDriver helper supports standard [CSS/XPath and text locators](/locators) as well as [Shadow DOM](/shadow) and [ARIA locators](/locators#aria-locators).
289
+
290
+ ### Grabbers
291
+
292
+ If you need to get element's value inside a test you can use `grab*` methods. They should be used with `await` operator inside `async` function:
293
+
294
+ ```js
295
+ import assert from 'assert';
296
+ Scenario('get value of current tasks', async ({ I }) => {
297
+ I.fillField('.todo', 'my first item');
298
+ I.pressKey('Enter')
299
+ I.fillField('.todo', 'my second item');
300
+ I.pressKey('Enter')
301
+ let numTodos = await I.grabTextFrom('.todo-count strong');
302
+ assert.equal(2, numTodos);
303
+ });
304
+ ```
305
+
306
+ ### Within
307
+
308
+ In case some actions should be taken inside one element (a container or modal window or iframe) you can use `within` block to narrow the scope.
309
+ Please take a note that you can't use within inside another within in Puppeteer helper:
310
+
311
+ ```js
312
+ await within('.todoapp', () => {
313
+ I.fillField('.todo', 'my new item');
314
+ I.pressKey('Enter')
315
+ I.see('1 item left', '.todo-count');
316
+ I.click('.todo-list input.toggle');
317
+ });
318
+ I.see('0 items left', '.todo-count');
319
+ ```
320
+
321
+ ### Each Element <Badge text="Since 3.3" type="warning"/>
322
+
323
+ Usually, CodeceptJS performs an action on the first matched element.
324
+ In case you want to do an action on each element found, use the special function `eachElement` which comes from [eachElement](https://codecept.io/plugins/#eachelement) plugin.
325
+
326
+ `eachElement` function matches all elements by locator and performs a callback on each of those element. A callback function receives element of webdriverio. `eachElement` may perform arbitrary actions on a page, so the first argument should by a description of the actions performed. This description will be used for logging purposes.
327
+
328
+ Usage example
329
+
330
+ ```js
331
+ await eachElement(
332
+ 'click all checkboxes',
333
+ 'input.custom-checkbox',
334
+ async (el, index) => {
335
+ await el.click();
336
+ });
337
+ );
338
+ ```
339
+
340
+ > ℹ Learn more about [eachElement plugin](/plugins/#eachelement)
341
+
342
+
343
+ ## Waiting
344
+
345
+ Web applications do not always respond instantly. That's why WebDriver protocol has methods to wait for changes on a page. CodeceptJS provides such commands prefixed with `wait*` so you could explicitly define what effects we wait for.
346
+
347
+ Most popular "waiters" are:
348
+
349
+ * `waitForText` - wait for text to appear on a page
350
+ * `waitForElement` - wait for element to appear on a page
351
+ * `waitForInvisible` - wait element to become invisible.
352
+
353
+ By default, they will wait for 1 second. This number can be changed in WebDriver configuration:
354
+
355
+ ```js
356
+ // inside codecept.conf.js
357
+ export const config = {
358
+ helpers: {
359
+ WebDriver: {
360
+ // WebDriver config goes here
361
+ // wait for 5 seconds
362
+ waitForTimeout: 5000
363
+ }
364
+ }
365
+ }
366
+ ```
367
+
368
+ ## SmartWait
369
+
370
+ It is possible to wait for elements pragmatically. If a test uses element which is not on a page yet, CodeceptJS will wait for few extra seconds before failing. This feature is based on [Implicit Wait](https://www.seleniumhq.org/docs/04_webdriver_advanced.jsp#implicit-waits) of Selenium. CodeceptJS enables implicit wait only when searching for a specific element and disables in all other cases. Thus, the performance of a test is not affected.
371
+
372
+ SmartWait can be enabled by setting wait option in WebDriver config.
373
+ Add `smartWait: 5000` to wait for additional 5s.
374
+
375
+ ```js
376
+ // inside codecept.conf.js
377
+ export const config = {
378
+ helpers: {
379
+ WebDriver: {
380
+ // WebDriver config goes here
381
+ // smart wait for 5 seconds
382
+ smartWait: 5000
383
+ }
384
+ }
385
+ }
386
+ ```
387
+
388
+ SmartWait works with a CSS/XPath locators in `click`, `seeElement` and other methods. See where it is enabled and where is not:
389
+
390
+ ```js
391
+ I.click('Login'); // DISABLED, not a locator
392
+ I.fillField('user', 'davert'); // DISABLED, not a specific locator
393
+ I.fillField({name: 'password'}, '123456'); // ENABLED, strict locator
394
+ I.click('#login'); // ENABLED, locator is CSS ID
395
+ I.see('Hello, Davert'); // DISABLED, Not a locator
396
+ I.seeElement('#userbar'); // ENABLED
397
+ I.dontSeeElement('#login'); // DISABLED, can't wait for element to hide
398
+ I.seeNumberOfElements('button.link', 5); // DISABLED, can wait only for one element
399
+
400
+ ```
401
+
402
+ SmartWait doesn't check element for visibility, so tests may fail even element is on a page.
403
+
404
+ Usage example:
405
+
406
+ ```js
407
+ // we use smartWait: 5000 instead of
408
+ // I.waitForElement('#click-me', 5);
409
+ // to wait for element on page
410
+ I.click('#click-me');
411
+ ```
412
+
413
+ If it's hard to define what to wait, it is recommended to use [retries](/basics/#retries) to rerun flaky steps.
414
+
415
+ ## Configuring CI
416
+
417
+ Locally, WebdriverIO starts the driver for you and tests run in window mode. On a remote CI (Continuous Integration) server there is usually no desktop, so window mode is not available.
418
+
419
+ There are following options available:
420
+
421
+ * Use headless Chrome or Firefox.
422
+ * Use [Selenoid](/plugins/selenoid) to run browsers inside Docker containers.
423
+ * Use paid [cloud services (SauceLabs, BrowserStack, TestingBot)](/helpers/WebDriver#cloud-providers).
424
+
425
+ ## Video Recording
426
+
427
+ When [Selenoid Plugin](/plugins#selenoid) is enabled video can be automatically recorded for each test.
428
+
429
+ ## Auto Login
430
+
431
+ To share the same user session across different tests CodeceptJS provides [autoLogin plugin](/plugins#autologin). It simplifies login management and reduces time consuming login operations. Instead of filling in login form before each test it saves the cookies of a valid user session and reuses it for next tests. If a session expires or doesn't exist, logs in a user again.
432
+
433
+ This plugin requires some configuration but is very simple in use:
434
+
435
+ ```js
436
+ Scenario('do something with logged in user', ({ I, login }) => {
437
+ login('user');
438
+ I.see('Dashboard','h1');
439
+ });
440
+ ```
441
+
442
+ With `autoLogin` plugin you can save cookies into a file and reuse same session on different runs.
443
+
444
+ > [▶ How to set up autoLogin plugin](/plugins#autologin)
445
+
446
+
447
+ ## Multiple Windows
448
+
449
+ CodeceptJS allows to use several browser windows inside a test. Sometimes we are testing the functionality of websites that we cannot control, such as a closed-source managed package, and there are popups that either remain open for configuring data on the screen, or close as a result of clicking a window. We can use these functions in order to gain more control over which page is being tested with Codecept at any given time. For example:
450
+
451
+ ```js
452
+ import assert from 'assert';
453
+
454
+ Scenario('should open main page of configured site, open a popup, switch to main page, then switch to popup, close popup, and go back to main page', async ({ I }) => {
455
+ I.amOnPage('/');
456
+ const handleBeforePopup = await I.grabCurrentWindowHandle();
457
+ const urlBeforePopup = await I.grabCurrentUrl();
458
+ const allHandlesBeforePopup = await I.grabAllWindowHandles();
459
+ assert.equal(allHandlesBeforePopup.length, 1, 'Single Window');
460
+
461
+ await I.executeScript(() => {
462
+ window.open('https://www.w3schools.com/', 'new window', 'toolbar=yes,scrollbars=yes,resizable=yes,width=400,height=400');
463
+ });
464
+
465
+ const allHandlesAfterPopup = await I.grabAllWindowHandles();
466
+ assert.equal(allHandlesAfterPopup.length, 2, 'Two Windows');
467
+
468
+ await I.switchToWindow(allHandlesAfterPopup[1]);
469
+ const urlAfterPopup = await I.grabCurrentUrl();
470
+ assert.equal(urlAfterPopup, 'https://www.w3schools.com/', 'Expected URL: Popup');
471
+
472
+ assert.equal(handleBeforePopup, allHandlesAfterPopup[0], 'Expected Window: Main Window');
473
+ await I.switchToWindow(handleBeforePopup);
474
+ const currentURL = await I.grabCurrentUrl();
475
+ assert.equal(currentURL, urlBeforePopup, 'Expected URL: Main URL');
476
+
477
+ await I.switchToWindow(allHandlesAfterPopup[1]);
478
+ const urlAfterSwitchBack = await I.grabCurrentUrl();
479
+ assert.equal(urlAfterSwitchBack, 'https://www.w3schools.com/', 'Expected URL: Popup');
480
+ await I.closeCurrentTab();
481
+
482
+ const allHandlesAfterPopupClosed = await I.grabAllWindowHandles();
483
+ assert.equal(allHandlesAfterPopupClosed.length, 1, 'Single Window');
484
+ const currentWindowHandle = await I.grabCurrentWindowHandle();
485
+ assert.equal(currentWindowHandle, allHandlesAfterPopup[0], 'Expected Window: Main Window');
486
+
487
+ });
488
+ ```
489
+
490
+ ## Mocking Requests
491
+
492
+ When testing web application you can disable some of external requests calls by enabling HTTP mocking.
493
+ This is useful when you want to isolate application testing from a backend. For instance, if you don't want to save data to database, and you know the request which performs save, you can mock the request, so application will treat this as valid response, but no data will be actually saved.
494
+
495
+ > **WebDriver has limited ability to mock requests**, so you can only mock only requests performed after page is loaded. This means that you can't block Google Analytics, or CDN calls, but you can mock API requests performed on user action.
496
+
497
+ To mock requests enable additional helper [MockRequest](/helpers/MockRequest) (which is based on Polly.js).
498
+
499
+ ```js
500
+ helpers: {
501
+ WebDriver: {
502
+ // regular WebDriver config here
503
+ },
504
+ MockRequest: {}
505
+ }
506
+ ```
507
+
508
+
509
+ The function `mockRequest` will be added to `I` object. You can use it to explicitly define which requests to block and which response they should return instead:
510
+
511
+ ```js
512
+ // block all Google Analytics calls
513
+ I.mockRequest('/google-analytics/*path', 200);
514
+ // return an empty successful response
515
+ I.mockRequest('GET', '/api/users', 200);
516
+ // block post requests to /api/users and return predefined object
517
+ I.mockRequest('POST', '/api/users', { user: 'davert' });
518
+ // return error request with body
519
+ I.mockRequest('GET', '/api/users/1', 404, { error: 'User not found' });
520
+ ```
521
+
522
+ > In WebDriver mocking is disabled every time a new page is loaded. Hence, `startMocking` method should be called and the mocks should be updated, after navigating to a new page. This is a limitation of WebDriver. Consider using Puppeteer with MockRequest instead.
523
+
524
+ ```js
525
+ I.amOnPage('/xyz');
526
+ I.mockRequest({ ... })
527
+ I.click('Go to Next Page');
528
+ // new page is loaded, mocking is disabled now. We need to set it up again
529
+ // in WebDriver as we can't detect that the page was reloaded, so no mocking :(
530
+ ```
531
+
532
+ > See [`mockRequest` API](/helpers/MockRequest#mockrequest)
533
+
534
+ To see `mockRequest` method in intellisense auto completion don't forget to run `codeceptjs def` command:
535
+
536
+ ```
537
+ npx codeceptjs def
538
+ ```
539
+
540
+ Mocking rules will be kept while a test is running. To stop mocking use `I.stopMocking()` command
541
+
542
+
543
+ ## Accessing webdriverio API
544
+
545
+ To get [webdriverio browser API](https://webdriver.io/docs/api.html) inside a test use [`I.useWebDriverTo`](/helpers/WebDriver/#usewebdriverto) method with a callback.
546
+ To keep test readable provide a description of a callback inside the first parameter.
547
+
548
+ ```js
549
+ I.useWebDriverTo('do something with native webdriverio api', async ({ browser }) => {
550
+ // use browser object here
551
+ });
552
+ ```
553
+
554
+ > webdriverio commands are asynchronous so a callback function must be async.
555
+
556
+ WebDriver helper can be obtained in this function as well. Use this to get full access to webdriverio elements inside the test.
557
+
558
+ ```js
559
+ I.useWebDriverTo('click all Save buttons', async (WebDriver) => {
560
+ const els = await WebDriver._locateClickable('Save');
561
+ for (let el of els) {
562
+ await el.click();
563
+ }
564
+ });
565
+ ```
566
+
567
+ ## Extending WebDriver
568
+
569
+ CodeceptJS doesn't aim to embrace all possible functionality of WebDriver. At some points you may find that some actions do not exist, however it is easy to add one. You will need to use WebDriver API from [webdriver.io](https://webdriver.io) library.
570
+
571
+ To create new actions which will be added into `I.` object you need to create a new helper. This can be done with `codeceptjs gh` command.
572
+
573
+ ```
574
+ npx codeceptjs gh
575
+ ```
576
+
577
+ Name a new helper "Web". Now each method of a created class can be added to I object. Be sure to enable this helper in config:
578
+
579
+ ```js
580
+ export const config = {
581
+ helpers: {
582
+ WebDriver: { /* WebDriver config goes here */ },
583
+ WebHelper: {
584
+ // load custom helper
585
+ require: './web_helper.js'
586
+ }
587
+ }
588
+ }
589
+ ```
590
+
591
+ > ℹ See [Custom Helper](/helpers) guide to see more examples.
592
+
593
+ While implementing custom actions using WebDriver API please note that, there is two versions of protocol: WebDriver and JSON Wire. Depending on a browser version one of those protocols can be used. We can't know for sure which protocol is going to used, so we will need to implement an action using both APIs.
594
+
595
+ ```js
596
+ const Helper = codeceptjs.helper;
597
+
598
+ class Web extends Helper {
599
+
600
+ // method to drag an item to coordinates
601
+ async dragToPoint(el, x, y) {
602
+ // access browser object from WebDriver
603
+ const browser = this.helpers.WebDriver.browser;
604
+ await this.helpers.WebDriver.moveCursorTo(el);
605
+
606
+ if (browser.isW3C) {
607
+ // we use WebDriver protocol
608
+ return browser.performActions([
609
+ {"type": "pointerDown", "button": 0},
610
+ {"type": "pointerMove", "origin": "pointer", "duration": 1000, x, y },
611
+ {"type": "pointerUp", "button": 0}
612
+ ]);
613
+ }
614
+
615
+ // we use JSON Wire protocol
616
+ await browser.buttonDown(0);
617
+ await browser.moveToElement(null, x, y);
618
+ await browser.buttonUp(0);
619
+ }
620
+
621
+ // method which restarts browser
622
+ async restartBrowser() {
623
+ const browser = this.helpers.WebDriver.browser;
624
+ await browser.reloadSession();
625
+ await browser.maximizeWindow();
626
+ }
627
+
628
+ // method which goes to previous page
629
+ async backToPreviousPage() {
630
+ const browser = this.helpers.WebDriver.browser;
631
+ await browser.back();
632
+ }
633
+ }
634
+ ```
635
+
636
+ When a helper is created, regenerate your step definitions, so you could see those actions when using [intellisense](/basics#intellisense):
637
+
638
+ ```
639
+ npx codeceptjs def
640
+ ```
641
+
package/docs/within.md ADDED
@@ -0,0 +1,55 @@
1
+ ---
2
+ permalink: /within
3
+ title: Within
4
+ ---
5
+
6
+ # Within
7
+
8
+ `within` scopes all actions inside it to a specific element on the page — useful when working with repeated UI components or narrowing interaction to a specific section.
9
+
10
+ ```js
11
+ within('.js-signup-form', () => {
12
+ I.fillField('user[login]', 'User')
13
+ I.fillField('user[email]', 'user@user.com')
14
+ I.fillField('user[password]', 'user@user.com')
15
+ I.click('button')
16
+ })
17
+ I.see('There were problems creating your account.')
18
+ ```
19
+
20
+ > ⚠ `within` can cause problems when used incorrectly. If you see unexpected behavior, refactor to use the context parameter on individual actions instead (e.g. `I.click('Login', '.nav')`). Keep `within` for the simplest cases.
21
+ > Since `within` returns a Promise, always `await` it when you need its return value.
22
+
23
+ ## IFrames
24
+
25
+ Use a `frame` locator to scope actions inside an iframe:
26
+
27
+ ```js
28
+ within({ frame: '#editor' }, () => {
29
+ I.see('Page')
30
+ I.fillField('Body', 'Hello world')
31
+ })
32
+ ```
33
+
34
+ Nested iframes _(WebDriver & Puppeteer only)_:
35
+
36
+ ```js
37
+ within({ frame: ['.content', '#editor'] }, () => {
38
+ I.see('Page')
39
+ })
40
+ ```
41
+
42
+ > ℹ IFrames can also be accessed via `I.switchTo` command.
43
+
44
+ ## Returning Values
45
+
46
+ `within` can return a value for use in the scenario:
47
+
48
+ ```js
49
+ const val = await within('#sidebar', () => {
50
+ return I.grabTextFrom({ css: 'h1' })
51
+ })
52
+ I.fillField('Description', val)
53
+ ```
54
+
55
+ When running steps inside a `within` block, they will be shown indented in the output.