codeceptjs 3.4.1 → 3.5.1-2.beta.7

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 (281) hide show
  1. package/README.md +31 -30
  2. package/bin/codecept.js +1 -1
  3. package/lib/actor.js +6 -3
  4. package/lib/ai.js +180 -0
  5. package/lib/cli.js +13 -3
  6. package/lib/codecept.js +8 -0
  7. package/lib/colorUtils.js +10 -0
  8. package/lib/command/definitions.js +2 -7
  9. package/lib/command/dryRun.js +11 -2
  10. package/lib/command/generate.js +46 -3
  11. package/lib/command/info.js +24 -0
  12. package/lib/command/init.js +64 -6
  13. package/lib/command/interactive.js +15 -1
  14. package/lib/command/run-multiple/collection.js +17 -5
  15. package/lib/command/run-multiple.js +4 -2
  16. package/lib/command/run-workers.js +68 -5
  17. package/lib/command/run.js +7 -0
  18. package/lib/command/workers/runTests.js +39 -0
  19. package/lib/container.js +13 -3
  20. package/lib/data/context.js +14 -6
  21. package/lib/event.js +4 -0
  22. package/lib/helper/ApiDataFactory.js +2 -1
  23. package/lib/helper/Appium.js +116 -29
  24. package/lib/helper/Expect.js +422 -0
  25. package/lib/helper/FileSystem.js +1 -1
  26. package/lib/helper/GraphQL.js +25 -0
  27. package/lib/helper/JSONResponse.js +4 -4
  28. package/lib/helper/Nightmare.js +10 -5
  29. package/lib/helper/OpenAI.js +126 -0
  30. package/lib/helper/Playwright.js +1298 -229
  31. package/lib/helper/Protractor.js +12 -7
  32. package/lib/helper/Puppeteer.js +204 -64
  33. package/lib/helper/REST.js +15 -5
  34. package/lib/helper/TestCafe.js +45 -10
  35. package/lib/helper/WebDriver.js +252 -83
  36. package/lib/helper/errors/ElementNotFound.js +2 -1
  37. package/lib/helper/extras/PlaywrightReactVueLocator.js +38 -0
  38. package/lib/helper/scripts/blurElement.js +17 -0
  39. package/lib/helper/scripts/focusElement.js +17 -0
  40. package/lib/helper/scripts/highlightElement.js +20 -0
  41. package/lib/html.js +258 -0
  42. package/lib/interfaces/bdd.js +1 -1
  43. package/lib/interfaces/gherkin.js +37 -3
  44. package/lib/interfaces/scenarioConfig.js +1 -0
  45. package/lib/listener/retry.js +2 -1
  46. package/lib/locator.js +17 -4
  47. package/lib/mochaFactory.js +2 -1
  48. package/lib/output.js +1 -1
  49. package/lib/pause.js +78 -19
  50. package/lib/plugin/autoLogin.js +45 -10
  51. package/lib/plugin/debugErrors.js +67 -0
  52. package/lib/plugin/fakerTransform.js +4 -6
  53. package/lib/plugin/heal.js +209 -0
  54. package/lib/plugin/retryFailedStep.js +10 -1
  55. package/lib/plugin/retryTo.js +2 -4
  56. package/lib/plugin/screenshotOnFail.js +11 -2
  57. package/lib/plugin/selenoid.js +6 -1
  58. package/lib/plugin/standardActingHelpers.js +0 -2
  59. package/lib/plugin/stepByStepReport.js +2 -2
  60. package/lib/plugin/tryTo.js +5 -7
  61. package/lib/plugin/wdio.js +0 -1
  62. package/lib/recorder.js +22 -11
  63. package/lib/secret.js +5 -4
  64. package/lib/session.js +1 -1
  65. package/lib/step.js +36 -12
  66. package/lib/ui.js +5 -3
  67. package/lib/utils.js +22 -1
  68. package/lib/workers.js +83 -10
  69. package/package.json +117 -95
  70. package/translations/de-DE.js +5 -0
  71. package/translations/fr-FR.js +14 -1
  72. package/translations/it-IT.js +1 -0
  73. package/translations/ja-JP.js +14 -9
  74. package/translations/pl-PL.js +5 -0
  75. package/translations/pt-BR.js +1 -0
  76. package/translations/ru-RU.js +1 -0
  77. package/translations/zh-CN.js +5 -0
  78. package/translations/zh-TW.js +5 -0
  79. package/typings/index.d.ts +51 -15
  80. package/typings/promiseBasedTypes.d.ts +864 -802
  81. package/typings/types.d.ts +1339 -744
  82. package/CHANGELOG.md +0 -2427
  83. package/docs/advanced.md +0 -351
  84. package/docs/api.md +0 -323
  85. package/docs/basics.md +0 -980
  86. package/docs/bdd.md +0 -535
  87. package/docs/best.md +0 -237
  88. package/docs/books.md +0 -37
  89. package/docs/bootstrap.md +0 -135
  90. package/docs/build/ApiDataFactory.js +0 -409
  91. package/docs/build/Appium.js +0 -1938
  92. package/docs/build/FileSystem.js +0 -228
  93. package/docs/build/GraphQL.js +0 -204
  94. package/docs/build/GraphQLDataFactory.js +0 -309
  95. package/docs/build/JSONResponse.js +0 -338
  96. package/docs/build/Mochawesome.js +0 -71
  97. package/docs/build/Nightmare.js +0 -2145
  98. package/docs/build/Playwright.js +0 -3986
  99. package/docs/build/Polly.js +0 -42
  100. package/docs/build/Protractor.js +0 -2699
  101. package/docs/build/Puppeteer.js +0 -3710
  102. package/docs/build/REST.js +0 -334
  103. package/docs/build/SeleniumWebdriver.js +0 -76
  104. package/docs/build/TestCafe.js +0 -2057
  105. package/docs/build/WebDriver.js +0 -4017
  106. package/docs/changelog.md +0 -2436
  107. package/docs/commands.md +0 -254
  108. package/docs/community-helpers.md +0 -58
  109. package/docs/configuration.md +0 -157
  110. package/docs/continuous-integration.md +0 -22
  111. package/docs/custom-helpers.md +0 -306
  112. package/docs/data.md +0 -375
  113. package/docs/detox.md +0 -235
  114. package/docs/docker.md +0 -137
  115. package/docs/email.md +0 -183
  116. package/docs/examples.md +0 -149
  117. package/docs/helpers/ApiDataFactory.md +0 -266
  118. package/docs/helpers/Appium.md +0 -1312
  119. package/docs/helpers/Detox.md +0 -586
  120. package/docs/helpers/FileSystem.md +0 -152
  121. package/docs/helpers/GraphQL.md +0 -130
  122. package/docs/helpers/GraphQLDataFactory.md +0 -226
  123. package/docs/helpers/JSONResponse.md +0 -254
  124. package/docs/helpers/Mochawesome.md +0 -8
  125. package/docs/helpers/MockRequest.md +0 -377
  126. package/docs/helpers/Nightmare.md +0 -1256
  127. package/docs/helpers/Playwright.md +0 -2208
  128. package/docs/helpers/Polly.md +0 -44
  129. package/docs/helpers/Puppeteer-firefox.md +0 -86
  130. package/docs/helpers/Puppeteer.md +0 -2141
  131. package/docs/helpers/REST.md +0 -217
  132. package/docs/helpers/TestCafe.md +0 -1222
  133. package/docs/helpers/WebDriver.md +0 -2319
  134. package/docs/hooks.md +0 -340
  135. package/docs/index.md +0 -111
  136. package/docs/installation.md +0 -75
  137. package/docs/internal-api.md +0 -265
  138. package/docs/locators.md +0 -331
  139. package/docs/mobile-react-native-locators.md +0 -67
  140. package/docs/mobile.md +0 -297
  141. package/docs/nightmare.md +0 -223
  142. package/docs/pageobjects.md +0 -291
  143. package/docs/parallel.md +0 -232
  144. package/docs/playwright.md +0 -609
  145. package/docs/plugins.md +0 -1171
  146. package/docs/puppeteer.md +0 -316
  147. package/docs/quickstart.md +0 -163
  148. package/docs/react.md +0 -69
  149. package/docs/reports.md +0 -392
  150. package/docs/secrets.md +0 -30
  151. package/docs/shadow.md +0 -68
  152. package/docs/shared/keys.mustache +0 -31
  153. package/docs/shared/react.mustache +0 -1
  154. package/docs/testcafe.md +0 -174
  155. package/docs/translation.md +0 -247
  156. package/docs/tutorial.md +0 -271
  157. package/docs/typescript.md +0 -180
  158. package/docs/ui.md +0 -59
  159. package/docs/videos.md +0 -28
  160. package/docs/visual.md +0 -202
  161. package/docs/vue.md +0 -121
  162. package/docs/webapi/amOnPage.mustache +0 -11
  163. package/docs/webapi/appendField.mustache +0 -9
  164. package/docs/webapi/attachFile.mustache +0 -12
  165. package/docs/webapi/checkOption.mustache +0 -13
  166. package/docs/webapi/clearCookie.mustache +0 -10
  167. package/docs/webapi/clearField.mustache +0 -9
  168. package/docs/webapi/click.mustache +0 -25
  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/dontSeeCurrentUrlEquals.mustache +0 -10
  176. package/docs/webapi/dontSeeElement.mustache +0 -8
  177. package/docs/webapi/dontSeeElementInDOM.mustache +0 -8
  178. package/docs/webapi/dontSeeInCurrentUrl.mustache +0 -4
  179. package/docs/webapi/dontSeeInField.mustache +0 -11
  180. package/docs/webapi/dontSeeInSource.mustache +0 -8
  181. package/docs/webapi/dontSeeInTitle.mustache +0 -8
  182. package/docs/webapi/doubleClick.mustache +0 -13
  183. package/docs/webapi/downloadFile.mustache +0 -12
  184. package/docs/webapi/dragAndDrop.mustache +0 -9
  185. package/docs/webapi/dragSlider.mustache +0 -11
  186. package/docs/webapi/executeAsyncScript.mustache +0 -24
  187. package/docs/webapi/executeScript.mustache +0 -26
  188. package/docs/webapi/fillField.mustache +0 -16
  189. package/docs/webapi/forceClick.mustache +0 -28
  190. package/docs/webapi/forceRightClick.mustache +0 -18
  191. package/docs/webapi/grabAllWindowHandles.mustache +0 -7
  192. package/docs/webapi/grabAttributeFrom.mustache +0 -10
  193. package/docs/webapi/grabAttributeFromAll.mustache +0 -9
  194. package/docs/webapi/grabBrowserLogs.mustache +0 -9
  195. package/docs/webapi/grabCookie.mustache +0 -11
  196. package/docs/webapi/grabCssPropertyFrom.mustache +0 -11
  197. package/docs/webapi/grabCssPropertyFromAll.mustache +0 -10
  198. package/docs/webapi/grabCurrentUrl.mustache +0 -9
  199. package/docs/webapi/grabCurrentWindowHandle.mustache +0 -6
  200. package/docs/webapi/grabDataFromPerformanceTiming.mustache +0 -20
  201. package/docs/webapi/grabElementBoundingRect.mustache +0 -20
  202. package/docs/webapi/grabGeoLocation.mustache +0 -8
  203. package/docs/webapi/grabHTMLFrom.mustache +0 -10
  204. package/docs/webapi/grabHTMLFromAll.mustache +0 -9
  205. package/docs/webapi/grabNumberOfOpenTabs.mustache +0 -8
  206. package/docs/webapi/grabNumberOfVisibleElements.mustache +0 -9
  207. package/docs/webapi/grabPageScrollPosition.mustache +0 -8
  208. package/docs/webapi/grabPopupText.mustache +0 -5
  209. package/docs/webapi/grabSource.mustache +0 -8
  210. package/docs/webapi/grabTextFrom.mustache +0 -10
  211. package/docs/webapi/grabTextFromAll.mustache +0 -9
  212. package/docs/webapi/grabTitle.mustache +0 -8
  213. package/docs/webapi/grabValueFrom.mustache +0 -9
  214. package/docs/webapi/grabValueFromAll.mustache +0 -8
  215. package/docs/webapi/moveCursorTo.mustache +0 -12
  216. package/docs/webapi/openNewTab.mustache +0 -7
  217. package/docs/webapi/pressKey.mustache +0 -12
  218. package/docs/webapi/pressKeyDown.mustache +0 -12
  219. package/docs/webapi/pressKeyUp.mustache +0 -12
  220. package/docs/webapi/pressKeyWithKeyNormalization.mustache +0 -60
  221. package/docs/webapi/refreshPage.mustache +0 -6
  222. package/docs/webapi/resizeWindow.mustache +0 -6
  223. package/docs/webapi/rightClick.mustache +0 -14
  224. package/docs/webapi/saveElementScreenshot.mustache +0 -10
  225. package/docs/webapi/saveScreenshot.mustache +0 -12
  226. package/docs/webapi/say.mustache +0 -10
  227. package/docs/webapi/scrollIntoView.mustache +0 -11
  228. package/docs/webapi/scrollPageToBottom.mustache +0 -6
  229. package/docs/webapi/scrollPageToTop.mustache +0 -6
  230. package/docs/webapi/scrollTo.mustache +0 -12
  231. package/docs/webapi/see.mustache +0 -11
  232. package/docs/webapi/seeAttributesOnElements.mustache +0 -9
  233. package/docs/webapi/seeCheckboxIsChecked.mustache +0 -10
  234. package/docs/webapi/seeCookie.mustache +0 -8
  235. package/docs/webapi/seeCssPropertiesOnElements.mustache +0 -9
  236. package/docs/webapi/seeCurrentUrlEquals.mustache +0 -11
  237. package/docs/webapi/seeElement.mustache +0 -8
  238. package/docs/webapi/seeElementInDOM.mustache +0 -8
  239. package/docs/webapi/seeInCurrentUrl.mustache +0 -8
  240. package/docs/webapi/seeInField.mustache +0 -12
  241. package/docs/webapi/seeInPopup.mustache +0 -8
  242. package/docs/webapi/seeInSource.mustache +0 -7
  243. package/docs/webapi/seeInTitle.mustache +0 -8
  244. package/docs/webapi/seeNumberOfElements.mustache +0 -11
  245. package/docs/webapi/seeNumberOfVisibleElements.mustache +0 -10
  246. package/docs/webapi/seeTextEquals.mustache +0 -9
  247. package/docs/webapi/seeTitleEquals.mustache +0 -8
  248. package/docs/webapi/selectOption.mustache +0 -21
  249. package/docs/webapi/setCookie.mustache +0 -16
  250. package/docs/webapi/setGeoLocation.mustache +0 -12
  251. package/docs/webapi/switchTo.mustache +0 -9
  252. package/docs/webapi/switchToNextTab.mustache +0 -10
  253. package/docs/webapi/switchToPreviousTab.mustache +0 -10
  254. package/docs/webapi/type.mustache +0 -18
  255. package/docs/webapi/uncheckOption.mustache +0 -13
  256. package/docs/webapi/wait.mustache +0 -8
  257. package/docs/webapi/waitForClickable.mustache +0 -11
  258. package/docs/webapi/waitForDetached.mustache +0 -10
  259. package/docs/webapi/waitForElement.mustache +0 -11
  260. package/docs/webapi/waitForEnabled.mustache +0 -6
  261. package/docs/webapi/waitForFunction.mustache +0 -17
  262. package/docs/webapi/waitForInvisible.mustache +0 -10
  263. package/docs/webapi/waitForText.mustache +0 -13
  264. package/docs/webapi/waitForValue.mustache +0 -10
  265. package/docs/webapi/waitForVisible.mustache +0 -10
  266. package/docs/webapi/waitInUrl.mustache +0 -9
  267. package/docs/webapi/waitNumberOfVisibleElements.mustache +0 -10
  268. package/docs/webapi/waitToHide.mustache +0 -10
  269. package/docs/webapi/waitUrlEquals.mustache +0 -10
  270. package/docs/webdriver.md +0 -657
  271. package/docs/wiki/Books-&-Posts.md +0 -27
  272. package/docs/wiki/Community-Helpers-&-Plugins.md +0 -49
  273. package/docs/wiki/Converting-Playwright-to-Istanbul-Coverage.md +0 -29
  274. package/docs/wiki/Examples.md +0 -139
  275. package/docs/wiki/Google-Summer-of-Code-(GSoC)-2020.md +0 -68
  276. package/docs/wiki/Home.md +0 -16
  277. package/docs/wiki/Release-Process.md +0 -24
  278. package/docs/wiki/Roadmap.md +0 -23
  279. package/docs/wiki/Tests.md +0 -1393
  280. package/docs/wiki/Upgrading-to-CodeceptJS-3.md +0 -153
  281. package/docs/wiki/Videos.md +0 -19
@@ -5,6 +5,7 @@ const path = require('path');
5
5
  const fs = require('fs');
6
6
 
7
7
  const Helper = require('@codeceptjs/helper');
8
+ const crypto = require('crypto');
8
9
  const stringIncludes = require('../assert/include').includes;
9
10
  const { urlEquals, equals } = require('../assert/equal');
10
11
  const { debug } = require('../output');
@@ -27,6 +28,10 @@ const {
27
28
  const ElementNotFound = require('./errors/ElementNotFound');
28
29
  const ConnectionRefused = require('./errors/ConnectionRefused');
29
30
  const Locator = require('../locator');
31
+ const { highlightElement } = require('./scripts/highlightElement');
32
+ const store = require('../store');
33
+ const { focusElement } = require('./scripts/focusElement');
34
+ const { blurElement } = require('./scripts/blurElement');
30
35
 
31
36
  const SHADOW = 'shadow';
32
37
  const webRoot = 'body';
@@ -39,7 +44,7 @@ const webRoot = 'body';
39
44
  * @typedef WebDriverConfig
40
45
  * @type {object}
41
46
  * @prop {string} url - base url of website to be tested.
42
- * @prop {string} browser browser in which to perform testing.
47
+ * @prop {string} browser - Browser in which to perform testing.
43
48
  * @prop {string} [basicAuth] - (optional) the basic authentication to pass to base url. Example: {username: 'username', password: 'password'}
44
49
  * @prop {string} [host=localhost] - WebDriver host to connect.
45
50
  * @prop {number} [port=4444] - WebDriver port to connect.
@@ -57,6 +62,9 @@ const webRoot = 'body';
57
62
  * @prop {object} [desiredCapabilities] Selenium's [desired capabilities](https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities).
58
63
  * @prop {boolean} [manualStart=false] - do not start browser before a test, start it manually inside a helper with `this.helpers["WebDriver"]._startBrowser()`.
59
64
  * @prop {object} [timeouts] [WebDriver timeouts](http://webdriver.io/docs/timeouts.html) defined as hash.
65
+ * @prop {boolean} [highlightElement] - highlight the interacting elements. Default: false. Note: only activate under verbose mode (--verbose).
66
+ * @prop {string} [logLevel=silent] - level of logging verbosity. Default: silent. Options: trace | debug | info | warn | error | silent. More info: https://webdriver.io/docs/configuration/#loglevel
67
+ * @prop {boolean} [devtoolsProtocol=false] - enable devtools protocol. Default: false. More info: https://webdriver.io/docs/automationProtocols/#devtools-protocol.
60
68
  */
61
69
  const config = {};
62
70
 
@@ -66,6 +74,13 @@ const config = {};
66
74
  *
67
75
  * WebDriver requires Selenium Server and ChromeDriver/GeckoDriver to be installed. Those tools can be easily installed via NPM. Please check [Testing with WebDriver](https://codecept.io/webdriver/#testing-with-webdriver) for more details.
68
76
  *
77
+ * With the release of WebdriverIO version v8.14.0, and onwards, all driver management hassles are now a thing of the past 🙌. Read more [here](https://webdriver.io/blog/2023/07/31/driver-management/).
78
+ * One of the significant advantages of this update is that you can now get rid of any driver services you previously had to manage, such as
79
+ * `wdio-chromedriver-service`, `wdio-geckodriver-service`, `wdio-edgedriver-service`, `wdio-safaridriver-service`, and even `@wdio/selenium-standalone-service`.
80
+ *
81
+ * For those who require custom driver options, fear not; WebDriver Helper allows you to pass in driver options through custom WebDriver configuration.
82
+ * If you have a custom grid, use a cloud service, or prefer to run your own driver, there's no need to worry since WebDriver Helper will only start a driver when there are no other connection information settings like hostname or port specified.
83
+ *
69
84
  * <!-- configuration -->
70
85
  *
71
86
  * Example:
@@ -87,6 +102,28 @@ const config = {};
87
102
  * }
88
103
  * ```
89
104
  *
105
+ * 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.
106
+ * For example:
107
+ *
108
+ * ```js
109
+ * {
110
+ * helpers: {
111
+ * WebDriver : {
112
+ * smartWait: 5000,
113
+ * browser: "chrome",
114
+ * browserVersion: '116.0.5793.0', // or 'stable', 'beta', 'dev' or 'canary'
115
+ * restart: false,
116
+ * windowSize: "maximize",
117
+ * timeouts: {
118
+ * "script": 60000,
119
+ * "page load": 10000
120
+ * }
121
+ * }
122
+ * }
123
+ * }
124
+ * ```
125
+ *
126
+ *
90
127
  * Example with basic authentication
91
128
  * ```js
92
129
  * {
@@ -127,6 +164,25 @@ const config = {};
127
164
  * }
128
165
  * ```
129
166
  *
167
+ * ### Running with devtools protocol
168
+ *
169
+ * ```js
170
+ * {
171
+ * helpers: {
172
+ * WebDriver : {
173
+ * url: "http://localhost",
174
+ * browser: "chrome",
175
+ * devtoolsProtocol: true,
176
+ * desiredCapabilities: {
177
+ * chromeOptions: {
178
+ * args: [ "--headless", "--disable-gpu", "--no-sandbox" ]
179
+ * }
180
+ * }
181
+ * }
182
+ * }
183
+ * }
184
+ * ```
185
+ *
130
186
  * ### Internet Explorer
131
187
  *
132
188
  * Additional configuration params can be used from [IE options](https://seleniumhq.github.io/selenium/docs/api/rb/Selenium/WebDriver/IE/Options.html)
@@ -409,7 +465,6 @@ class WebDriver extends Helper {
409
465
  _validateConfig(config) {
410
466
  const defaults = {
411
467
  logLevel: 'silent',
412
- path: '/wd/hub',
413
468
  // codeceptjs
414
469
  remoteFileUpload: true,
415
470
  smartWait: 0,
@@ -423,17 +478,23 @@ class WebDriver extends Helper {
423
478
  keepCookies: false,
424
479
  keepBrowserState: false,
425
480
  deprecationWarnings: false,
481
+ highlightElement: false,
426
482
  };
427
483
 
428
484
  // override defaults with config
429
485
  config = Object.assign(defaults, config);
430
486
 
431
- if (typeof config.host !== 'undefined') config.hostname = config.host; // webdriverio spec
487
+ if (config.host) {
488
+ // webdriverio spec
489
+ config.hostname = config.host;
490
+ config.path = '/wd/hub';
491
+ }
432
492
  config.baseUrl = config.url || config.baseUrl;
433
493
  if (config.desiredCapabilities && Object.keys(config.desiredCapabilities).length) {
434
494
  config.capabilities = config.desiredCapabilities;
435
495
  }
436
496
  config.capabilities.browserName = config.browser || config.capabilities.browserName;
497
+ config.capabilities.browserVersion = config.browserVersion || config.capabilities.browserVersion;
437
498
  if (config.capabilities.chromeOptions) {
438
499
  config.capabilities['goog:chromeOptions'] = config.capabilities.chromeOptions;
439
500
  delete config.capabilities.chromeOptions;
@@ -535,6 +596,10 @@ class WebDriver extends Helper {
535
596
  delete this.options.capabilities.hostname;
536
597
  delete this.options.capabilities.port;
537
598
  delete this.options.capabilities.path;
599
+ if (this.options.devtoolsProtocol) {
600
+ if (!['chrome', 'chromium'].includes(this.options.browser.toLowerCase())) throw Error('The devtools protocol is only working with Chrome or Chromium');
601
+ this.options.automationProtocol = 'devtools';
602
+ }
538
603
  this.browser = await webdriverio.remote(this.options);
539
604
  }
540
605
  } catch (err) {
@@ -822,7 +887,7 @@ class WebDriver extends Helper {
822
887
  }
823
888
 
824
889
  /**
825
- * Find a checkbox by providing human readable text:
890
+ * Find a checkbox by providing human-readable text:
826
891
  *
827
892
  * ```js
828
893
  * this.helpers['WebDriver']._locateCheckable('I agree with terms and conditions').then // ...
@@ -835,7 +900,7 @@ class WebDriver extends Helper {
835
900
  }
836
901
 
837
902
  /**
838
- * Find a clickable element by providing human readable text:
903
+ * Find a clickable element by providing human-readable text:
839
904
  *
840
905
  * ```js
841
906
  * const els = await this.helpers.WebDriver._locateClickable('Next page');
@@ -850,7 +915,7 @@ class WebDriver extends Helper {
850
915
  }
851
916
 
852
917
  /**
853
- * Find field elements by providing human readable text:
918
+ * Find field elements by providing human-readable text:
854
919
  *
855
920
  * ```js
856
921
  * this.helpers['WebDriver']._locateFields('Your email').then // ...
@@ -862,6 +927,14 @@ class WebDriver extends Helper {
862
927
  return findFields.call(this, locator).then(res => res);
863
928
  }
864
929
 
930
+ /**
931
+ * {{> grabWebElements }}
932
+ *
933
+ */
934
+ async grabWebElements(locator) {
935
+ return this._locate(locator);
936
+ }
937
+
865
938
  /**
866
939
  * Set [WebDriver timeouts](https://webdriver.io/docs/timeouts.html) in realtime.
867
940
  *
@@ -914,6 +987,7 @@ class WebDriver extends Helper {
914
987
  assertElementExists(res, locator, 'Clickable element');
915
988
  }
916
989
  const elem = usingFirstElement(res);
990
+ highlightActiveElement.call(this, elem);
917
991
  return this.browser[clickMethod](getElementId(elem));
918
992
  }
919
993
 
@@ -932,6 +1006,7 @@ class WebDriver extends Helper {
932
1006
  assertElementExists(res, locator, 'Clickable element');
933
1007
  }
934
1008
  const elem = usingFirstElement(res);
1009
+ highlightActiveElement.call(this, elem);
935
1010
 
936
1011
  return this.executeScript((el) => {
937
1012
  if (document.activeElement instanceof HTMLElement) {
@@ -959,6 +1034,7 @@ class WebDriver extends Helper {
959
1034
  }
960
1035
 
961
1036
  const elem = usingFirstElement(res);
1037
+ highlightActiveElement.call(this, elem);
962
1038
  return elem.doubleClick();
963
1039
  }
964
1040
 
@@ -1024,7 +1100,9 @@ class WebDriver extends Helper {
1024
1100
  const res = await findFields.call(this, field);
1025
1101
  assertElementExists(res, field, 'Field');
1026
1102
  const elem = usingFirstElement(res);
1027
- return elem.setValue(value.toString());
1103
+ highlightActiveElement.call(this, elem);
1104
+ await elem.clearValue();
1105
+ await elem.setValue(value.toString());
1028
1106
  }
1029
1107
 
1030
1108
  /**
@@ -1035,7 +1113,12 @@ class WebDriver extends Helper {
1035
1113
  const res = await findFields.call(this, field);
1036
1114
  assertElementExists(res, field, 'Field');
1037
1115
  const elem = usingFirstElement(res);
1038
- return elem.addValue(value);
1116
+ highlightActiveElement.call(this, elem);
1117
+ if (this.options.automationProtocol) {
1118
+ const curentValue = await elem.getValue();
1119
+ return elem.setValue(curentValue + value.toString());
1120
+ }
1121
+ return elem.addValue(value.toString());
1039
1122
  }
1040
1123
 
1041
1124
  /**
@@ -1046,6 +1129,10 @@ class WebDriver extends Helper {
1046
1129
  const res = await findFields.call(this, field);
1047
1130
  assertElementExists(res, field, 'Field');
1048
1131
  const elem = usingFirstElement(res);
1132
+ highlightActiveElement.call(this, elem);
1133
+ if (this.options.automationProtocol) {
1134
+ return elem.setValue('');
1135
+ }
1049
1136
  return elem.clearValue(getElementId(elem));
1050
1137
  }
1051
1138
 
@@ -1056,6 +1143,7 @@ class WebDriver extends Helper {
1056
1143
  const res = await findFields.call(this, select);
1057
1144
  assertElementExists(res, select, 'Selectable field');
1058
1145
  const elem = usingFirstElement(res);
1146
+ highlightActiveElement.call(this, elem);
1059
1147
 
1060
1148
  if (!Array.isArray(option)) {
1061
1149
  option = [option];
@@ -1082,8 +1170,9 @@ class WebDriver extends Helper {
1082
1170
  }
1083
1171
 
1084
1172
  /**
1085
- * {{> attachFile }}
1086
1173
  * Appium: not tested
1174
+ *
1175
+ * {{> attachFile }}
1087
1176
  */
1088
1177
  async attachFile(locator, pathToFile) {
1089
1178
  let file = path.join(global.codecept_dir, pathToFile);
@@ -1097,7 +1186,7 @@ class WebDriver extends Helper {
1097
1186
  const el = usingFirstElement(res);
1098
1187
 
1099
1188
  // Remote Upload (when running Selenium Server)
1100
- if (this.options.remoteFileUpload) {
1189
+ if (this.options.remoteFileUpload && !this.options.automationProtocol) {
1101
1190
  try {
1102
1191
  this.debugSection('File', 'Uploading file to remote server');
1103
1192
  file = await this.browser.uploadFile(file);
@@ -1110,8 +1199,8 @@ class WebDriver extends Helper {
1110
1199
  }
1111
1200
 
1112
1201
  /**
1113
- * {{> checkOption }}
1114
1202
  * Appium: not tested
1203
+ * {{> checkOption }}
1115
1204
  */
1116
1205
  async checkOption(field, context = null) {
1117
1206
  const clickMethod = this.browser.isMobile && !this.browser.isW3C ? 'touchClick' : 'elementClick';
@@ -1122,6 +1211,7 @@ class WebDriver extends Helper {
1122
1211
  assertElementExists(res, field, 'Checkable');
1123
1212
  const elem = usingFirstElement(res);
1124
1213
  const elementId = getElementId(elem);
1214
+ highlightActiveElement.call(this, elem);
1125
1215
 
1126
1216
  const isSelected = await this.browser.isElementSelected(elementId);
1127
1217
  if (isSelected) return Promise.resolve(true);
@@ -1129,8 +1219,8 @@ class WebDriver extends Helper {
1129
1219
  }
1130
1220
 
1131
1221
  /**
1132
- * {{> uncheckOption }}
1133
1222
  * Appium: not tested
1223
+ * {{> uncheckOption }}
1134
1224
  */
1135
1225
  async uncheckOption(field, context = null) {
1136
1226
  const clickMethod = this.browser.isMobile && !this.browser.isW3C ? 'touchClick' : 'elementClick';
@@ -1141,6 +1231,7 @@ class WebDriver extends Helper {
1141
1231
  assertElementExists(res, field, 'Checkable');
1142
1232
  const elem = usingFirstElement(res);
1143
1233
  const elementId = getElementId(elem);
1234
+ highlightActiveElement.call(this, elem);
1144
1235
 
1145
1236
  const isSelected = await this.browser.isElementSelected(elementId);
1146
1237
  if (!isSelected) return Promise.resolve(true);
@@ -1332,7 +1423,8 @@ class WebDriver extends Helper {
1332
1423
  *
1333
1424
  */
1334
1425
  async seeInField(field, value) {
1335
- return proceedSeeField.call(this, 'assert', field, value);
1426
+ const _value = (typeof value === 'boolean') ? value : value.toString();
1427
+ return proceedSeeField.call(this, 'assert', field, _value);
1336
1428
  }
1337
1429
 
1338
1430
  /**
@@ -1340,20 +1432,21 @@ class WebDriver extends Helper {
1340
1432
  *
1341
1433
  */
1342
1434
  async dontSeeInField(field, value) {
1343
- return proceedSeeField.call(this, 'negate', field, value);
1435
+ const _value = (typeof value === 'boolean') ? value : value.toString();
1436
+ return proceedSeeField.call(this, 'negate', field, _value);
1344
1437
  }
1345
1438
 
1346
1439
  /**
1347
- * {{> seeCheckboxIsChecked }}
1348
1440
  * Appium: not tested
1441
+ * {{> seeCheckboxIsChecked }}
1349
1442
  */
1350
1443
  async seeCheckboxIsChecked(field) {
1351
1444
  return proceedSeeCheckbox.call(this, 'assert', field);
1352
1445
  }
1353
1446
 
1354
1447
  /**
1355
- * {{> dontSeeCheckboxIsChecked }}
1356
1448
  * Appium: not tested
1449
+ * {{> dontSeeCheckboxIsChecked }}
1357
1450
  */
1358
1451
  async dontSeeCheckboxIsChecked(field) {
1359
1452
  return proceedSeeCheckbox.call(this, 'negate', field);
@@ -1471,33 +1564,33 @@ class WebDriver extends Helper {
1471
1564
  async seeCssPropertiesOnElements(locator, cssProperties) {
1472
1565
  const res = await this._locate(locator);
1473
1566
  assertElementExists(res, locator);
1567
+
1568
+ const cssPropertiesCamelCase = convertCssPropertiesToCamelCase(cssProperties);
1474
1569
  const elemAmount = res.length;
1570
+ let props = [];
1475
1571
 
1476
- let props = await forEachAsync(res, async (el) => {
1477
- return forEachAsync(Object.keys(cssProperties), async (prop) => {
1478
- const propValue = await this.browser.getElementCSSValue(getElementId(el), prop);
1479
- if (isColorProperty(prop) && propValue && propValue.value) {
1480
- return convertColorToRGBA(propValue.value);
1572
+ for (const element of res) {
1573
+ for (const prop of Object.keys(cssProperties)) {
1574
+ const cssProp = await this.grabCssPropertyFrom(locator, prop);
1575
+ if (isColorProperty(prop)) {
1576
+ props.push(convertColorToRGBA(cssProp));
1577
+ } else {
1578
+ props.push(cssProp);
1481
1579
  }
1482
- return propValue;
1483
- });
1484
- });
1485
-
1486
- const cssPropertiesCamelCase = convertCssPropertiesToCamelCase(cssProperties);
1580
+ }
1581
+ }
1487
1582
 
1488
1583
  const values = Object.keys(cssPropertiesCamelCase).map(key => cssPropertiesCamelCase[key]);
1489
1584
  if (!Array.isArray(props)) props = [props];
1490
1585
  let chunked = chunkArray(props, values.length);
1491
1586
  chunked = chunked.filter((val) => {
1492
1587
  for (let i = 0; i < val.length; ++i) {
1493
- if (val[i] !== values[i]) return false;
1588
+ // eslint-disable-next-line eqeqeq
1589
+ if (val[i] != values[i]) return false;
1494
1590
  }
1495
1591
  return true;
1496
1592
  });
1497
- return assert.ok(
1498
- chunked.length === elemAmount,
1499
- `expected all elements (${(new Locator(locator))}) to have CSS property ${JSON.stringify(cssProperties)}`,
1500
- );
1593
+ return equals(`all elements (${(new Locator(locator))}) to have CSS property ${JSON.stringify(cssProperties)}`).assert(chunked.length, elemAmount);
1501
1594
  }
1502
1595
 
1503
1596
  /**
@@ -1517,7 +1610,9 @@ class WebDriver extends Helper {
1517
1610
  let chunked = chunkArray(attrs, values.length);
1518
1611
  chunked = chunked.filter((val) => {
1519
1612
  for (let i = 0; i < val.length; ++i) {
1520
- if (val[i] !== values[i]) return false;
1613
+ const _actual = Number.isNaN(val[i]) || (typeof values[i]) === 'string' ? val[i] : Number.parseInt(val[i], 10);
1614
+ const _expected = Number.isNaN(values[i]) || (typeof values[i]) === 'string' ? values[i] : Number.parseInt(values[i], 10);
1615
+ if (_actual !== _expected) return false;
1521
1616
  }
1522
1617
  return true;
1523
1618
  });
@@ -1576,10 +1671,9 @@ class WebDriver extends Helper {
1576
1671
  }
1577
1672
 
1578
1673
  /**
1579
- * {{> executeScript }}
1580
- *
1581
- *
1582
1674
  * Wraps [execute](http://webdriver.io/api/protocol/execute.html) command.
1675
+ *
1676
+ * {{> executeScript }}
1583
1677
  */
1584
1678
  executeScript(...args) {
1585
1679
  return this.browser.execute.apply(this.browser, args);
@@ -1642,7 +1736,11 @@ class WebDriver extends Helper {
1642
1736
  const res = await this._locate(withStrictLocator(locator), true);
1643
1737
  assertElementExists(res, locator);
1644
1738
  const elem = usingFirstElement(res);
1645
- return elem.moveTo({ xOffset, yOffset });
1739
+ try {
1740
+ await elem.moveTo({ xOffset, yOffset });
1741
+ } catch (e) {
1742
+ debug(e.message);
1743
+ }
1646
1744
  }
1647
1745
 
1648
1746
  /**
@@ -1701,11 +1799,8 @@ class WebDriver extends Helper {
1701
1799
  }
1702
1800
 
1703
1801
  /**
1802
+ * Uses Selenium's JSON [cookie format](https://code.google.com/p/selenium/wiki/JsonWireProtocol#Cookie_JSON_Object).
1704
1803
  * {{> setCookie }}
1705
- *
1706
- *
1707
- * Uses Selenium's JSON [cookie
1708
- * format](https://code.google.com/p/selenium/wiki/JsonWireProtocol#Cookie_JSON_Object).
1709
1804
  */
1710
1805
  async setCookie(cookie) {
1711
1806
  return this.browser.setCookies(cookie);
@@ -1758,7 +1853,7 @@ class WebDriver extends Helper {
1758
1853
  }
1759
1854
 
1760
1855
  /**
1761
- * Dismisses the active JavaScript popup, as created by window.alert|window.confirm|window.prompt.
1856
+ * Dismisses the active JavaScript popup, as created by `window.alert|window.confirm|window.prompt`.
1762
1857
  *
1763
1858
  */
1764
1859
  async cancelPopup() {
@@ -1832,9 +1927,9 @@ class WebDriver extends Helper {
1832
1927
  }
1833
1928
 
1834
1929
  /**
1835
- * {{> pressKeyWithKeyNormalization }}
1836
- *
1837
1930
  * _Note:_ In case a text field or textarea is focused be aware that some browsers do not respect active modifier when combining modifier keys with other keys.
1931
+ *
1932
+ * {{> pressKeyWithKeyNormalization }}
1838
1933
  */
1839
1934
  async pressKey(key) {
1840
1935
  const modifiers = [];
@@ -1879,6 +1974,7 @@ class WebDriver extends Helper {
1879
1974
  */
1880
1975
  async type(keys, delay = null) {
1881
1976
  if (!Array.isArray(keys)) {
1977
+ keys = keys.toString();
1882
1978
  keys = keys.split('');
1883
1979
  }
1884
1980
  if (delay) {
@@ -1892,11 +1988,12 @@ class WebDriver extends Helper {
1892
1988
  }
1893
1989
 
1894
1990
  /**
1895
- * {{> resizeWindow }}
1896
1991
  * Appium: not tested in web, in apps doesn't work
1992
+ *
1993
+ * {{> resizeWindow }}
1897
1994
  */
1898
1995
  async resizeWindow(width, height) {
1899
- return this._resizeBrowserWindow(this.browser, width, height);
1996
+ return this.browser.setWindowSize(width, height);
1900
1997
  }
1901
1998
 
1902
1999
  async _resizeBrowserWindow(browser, width, height) {
@@ -1921,8 +2018,32 @@ class WebDriver extends Helper {
1921
2018
  }
1922
2019
 
1923
2020
  /**
1924
- * {{> dragAndDrop }}
2021
+ * {{> focus }}
2022
+ *
2023
+ */
2024
+ async focus(locator) {
2025
+ const els = await this._locate(locator);
2026
+ assertElementExists(els, locator, 'Element to focus');
2027
+ const el = usingFirstElement(els);
2028
+
2029
+ await focusElement(el, this.browser);
2030
+ }
2031
+
2032
+ /**
2033
+ * {{> blur }}
2034
+ *
2035
+ */
2036
+ async blur(locator) {
2037
+ const els = await this._locate(locator);
2038
+ assertElementExists(els, locator, 'Element to blur');
2039
+ const el = usingFirstElement(els);
2040
+
2041
+ await blurElement(el, this.browser);
2042
+ }
2043
+
2044
+ /**
1925
2045
  * Appium: not tested
2046
+ * {{> dragAndDrop }}
1926
2047
  */
1927
2048
  async dragAndDrop(srcElement, destElement) {
1928
2049
  let sourceEl = await this._locate(srcElement);
@@ -2022,7 +2143,9 @@ class WebDriver extends Helper {
2022
2143
  * {{> wait }}
2023
2144
  */
2024
2145
  async wait(sec) {
2025
- return new Promise(resolve => setTimeout(resolve, sec * 1000));
2146
+ return new Promise(resolve => {
2147
+ setTimeout(resolve, sec * 1000);
2148
+ });
2026
2149
  }
2027
2150
 
2028
2151
  /**
@@ -2127,20 +2250,18 @@ class WebDriver extends Helper {
2127
2250
  const aSec = sec || this.options.waitForTimeoutInSeconds;
2128
2251
  const _context = context || this.root;
2129
2252
 
2130
- return this.browser.waitUntil(
2131
- async () => {
2132
- const res = await this.$$(withStrictLocator.call(this, _context));
2133
- if (!res || res.length === 0) return false;
2134
- const selected = await forEachAsync(res, async el => this.browser.getElementText(getElementId(el)));
2135
- if (Array.isArray(selected)) {
2136
- return selected.filter(part => part.indexOf(text) >= 0).length > 0;
2137
- }
2138
- return selected.indexOf(text) >= 0;
2139
- }, {
2140
- timeout: aSec * 1000,
2141
- timeoutMsg: `element (${_context}) is not in DOM or there is no element(${_context}) with text "${text}" after ${aSec} sec`,
2142
- },
2143
- );
2253
+ return this.browser.waitUntil(async () => {
2254
+ const res = await this.$$(withStrictLocator.call(this, _context));
2255
+ if (!res || res.length === 0) return false;
2256
+ const selected = await forEachAsync(res, async el => this.browser.getElementText(getElementId(el)));
2257
+ if (Array.isArray(selected)) {
2258
+ return selected.filter(part => part.indexOf(text) >= 0).length > 0;
2259
+ }
2260
+ return selected.indexOf(text) >= 0;
2261
+ }, {
2262
+ timeout: aSec * 1000,
2263
+ timeoutMsg: `element (${_context}) is not in DOM or there is no element(${_context}) with text "${text}" after ${aSec} sec`,
2264
+ });
2144
2265
  }
2145
2266
 
2146
2267
  /**
@@ -2150,20 +2271,18 @@ class WebDriver extends Helper {
2150
2271
  const client = this.browser;
2151
2272
  const aSec = sec || this.options.waitForTimeoutInSeconds;
2152
2273
 
2153
- return client.waitUntil(
2154
- async () => {
2155
- const res = await findFields.call(this, field);
2156
- if (!res || res.length === 0) return false;
2157
- const selected = await forEachAsync(res, async el => el.getValue());
2158
- if (Array.isArray(selected)) {
2159
- return selected.filter(part => part.indexOf(value) >= 0).length > 0;
2160
- }
2161
- return selected.indexOf(value) >= 0;
2162
- }, {
2163
- timeout: aSec * 1000,
2164
- timeoutMsg: `element (${field}) is not in DOM or there is no element(${field}) with value "${value}" after ${aSec} sec`,
2165
- },
2166
- );
2274
+ return client.waitUntil(async () => {
2275
+ const res = await findFields.call(this, field);
2276
+ if (!res || res.length === 0) return false;
2277
+ const selected = await forEachAsync(res, async el => el.getValue());
2278
+ if (Array.isArray(selected)) {
2279
+ return selected.filter(part => part.indexOf(value) >= 0).length > 0;
2280
+ }
2281
+ return selected.indexOf(value) >= 0;
2282
+ }, {
2283
+ timeout: aSec * 1000,
2284
+ timeoutMsg: `element (${field}) is not in DOM or there is no element(${field}) with value "${value}" after ${aSec} sec`,
2285
+ });
2167
2286
  }
2168
2287
 
2169
2288
  /**
@@ -2255,12 +2374,33 @@ class WebDriver extends Helper {
2255
2374
  return this.browser.waitUntil(async () => this.browser.execute(fn, ...args), { timeout: aSec * 1000, timeoutMsg: '' });
2256
2375
  }
2257
2376
 
2377
+ /**
2378
+ * {{> waitForNumberOfTabs }}
2379
+ */
2380
+ async waitForNumberOfTabs(expectedTabs, sec) {
2381
+ const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeoutInSeconds;
2382
+ let currentTabs;
2383
+ let count = 0;
2384
+
2385
+ do {
2386
+ currentTabs = await this.grabNumberOfOpenTabs();
2387
+ await this.wait(1);
2388
+ count += 1000;
2389
+ if (currentTabs >= expectedTabs) return;
2390
+ } while (count <= waitTimeout);
2391
+
2392
+ throw new Error(`Expected ${expectedTabs} tabs are not met after ${waitTimeout / 1000} sec.`);
2393
+ }
2394
+
2258
2395
  /**
2259
2396
  * {{> switchTo }}
2260
2397
  */
2261
2398
  async switchTo(locator) {
2262
2399
  this.browser.isInsideFrame = true;
2263
2400
  if (Number.isInteger(locator)) {
2401
+ if (this.options.automationProtocol) {
2402
+ return this.browser.switchToFrame(locator + 1);
2403
+ }
2264
2404
  return this.browser.switchToFrame(locator);
2265
2405
  }
2266
2406
  if (!locator) {
@@ -2371,8 +2511,11 @@ class WebDriver extends Helper {
2371
2511
  const body = document.body;
2372
2512
  const html = document.documentElement;
2373
2513
  window.scrollTo(0, Math.max(
2374
- body.scrollHeight, body.offsetHeight,
2375
- html.clientHeight, html.scrollHeight, html.offsetHeight
2514
+ body.scrollHeight,
2515
+ body.offsetHeight,
2516
+ html.clientHeight,
2517
+ html.scrollHeight,
2518
+ html.offsetHeight
2376
2519
  ));
2377
2520
  });
2378
2521
  /* eslint-enable */
@@ -2394,21 +2537,41 @@ class WebDriver extends Helper {
2394
2537
  }
2395
2538
 
2396
2539
  /**
2540
+ * This method is **deprecated**.
2541
+ *
2542
+ *
2397
2543
  * {{> setGeoLocation }}
2398
2544
  */
2399
- async setGeoLocation(latitude, longitude, altitude = null) {
2400
- if (altitude) {
2401
- return this.browser.setGeoLocation({ latitude, longitude });
2545
+ async setGeoLocation(latitude, longitude) {
2546
+ if (!this.options.automationProtocol) {
2547
+ console.log(`setGeoLocation deprecated:
2548
+ * This command is deprecated due to using deprecated JSON Wire Protocol command. More info: https://webdriver.io/docs/api/jsonwp/#setgeolocation
2549
+ * Switch to devtools protocol to use this command by setting devtoolsProtocol: true in the configuration`);
2550
+ return;
2402
2551
  }
2403
- return this.browser.setGeoLocation({ latitude, longitude, altitude });
2552
+ this.geoLocation = { latitude, longitude };
2553
+ const puppeteerBrowser = await this.browser.getPuppeteer();
2554
+ await this.browser.call(async () => {
2555
+ const pages = await puppeteerBrowser.pages();
2556
+ await pages[0].setGeolocation({ latitude, longitude });
2557
+ });
2404
2558
  }
2405
2559
 
2406
2560
  /**
2561
+ * This method is **deprecated**.
2562
+ *
2407
2563
  * {{> grabGeoLocation }}
2408
2564
  *
2409
2565
  */
2410
2566
  async grabGeoLocation() {
2411
- return this.browser.getGeoLocation();
2567
+ if (!this.options.automationProtocol) {
2568
+ console.log(`grabGeoLocation deprecated:
2569
+ * This command is deprecated due to using deprecated JSON Wire Protocol command. More info: https://webdriver.io/docs/api/jsonwp/#getgeolocation
2570
+ * Switch to devtools protocol to use this command by setting devtoolsProtocol: true in the configuration`);
2571
+ return;
2572
+ }
2573
+ if (!this.geoLocation) return 'No GeoLocation is set!';
2574
+ return this.geoLocation;
2412
2575
  }
2413
2576
 
2414
2577
  /**
@@ -2604,7 +2767,7 @@ async function proceedSeeField(assertType, field, value) {
2604
2767
  }
2605
2768
  };
2606
2769
 
2607
- const proceedSingle = el => this.browser.getElementAttribute(getElementId(el), 'value').then((res) => {
2770
+ const proceedSingle = el => el.getValue().then((res) => {
2608
2771
  if (res === null) {
2609
2772
  throw new Error(`Element ${el.selector} has no value attribute`);
2610
2773
  }
@@ -2873,6 +3036,12 @@ function isModifierKey(key) {
2873
3036
  return unicodeModifierKeys.includes(key);
2874
3037
  }
2875
3038
 
3039
+ function highlightActiveElement(element) {
3040
+ if (this.options.highlightElement && global.debugMode) {
3041
+ highlightElement(element, this.browser);
3042
+ }
3043
+ }
3044
+
2876
3045
  function prepareLocateFn(context) {
2877
3046
  if (!context) return this._locate.bind(this);
2878
3047
  return (l) => {