codeceptjs 4.0.0-beta.3 → 4.0.0-beta.5

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 (155) hide show
  1. package/README.md +134 -119
  2. package/bin/codecept.js +12 -2
  3. package/bin/test-server.js +53 -0
  4. package/docs/webapi/clearCookie.mustache +1 -1
  5. package/lib/actor.js +66 -102
  6. package/lib/ai.js +130 -121
  7. package/lib/assert/empty.js +3 -5
  8. package/lib/assert/equal.js +4 -7
  9. package/lib/assert/include.js +4 -6
  10. package/lib/assert/throws.js +2 -4
  11. package/lib/assert/truth.js +2 -2
  12. package/lib/codecept.js +141 -86
  13. package/lib/command/check.js +201 -0
  14. package/lib/command/configMigrate.js +2 -4
  15. package/lib/command/definitions.js +8 -26
  16. package/lib/command/dryRun.js +30 -35
  17. package/lib/command/generate.js +10 -14
  18. package/lib/command/gherkin/snippets.js +75 -73
  19. package/lib/command/gherkin/steps.js +1 -1
  20. package/lib/command/info.js +42 -8
  21. package/lib/command/init.js +13 -12
  22. package/lib/command/interactive.js +10 -2
  23. package/lib/command/list.js +1 -1
  24. package/lib/command/run-multiple/chunk.js +48 -45
  25. package/lib/command/run-multiple.js +12 -35
  26. package/lib/command/run-workers.js +21 -58
  27. package/lib/command/utils.js +5 -6
  28. package/lib/command/workers/runTests.js +263 -222
  29. package/lib/container.js +386 -238
  30. package/lib/data/context.js +10 -13
  31. package/lib/data/dataScenarioConfig.js +8 -8
  32. package/lib/data/dataTableArgument.js +6 -6
  33. package/lib/data/table.js +5 -11
  34. package/lib/effects.js +223 -0
  35. package/lib/element/WebElement.js +327 -0
  36. package/lib/els.js +158 -0
  37. package/lib/event.js +21 -17
  38. package/lib/heal.js +88 -80
  39. package/lib/helper/AI.js +2 -1
  40. package/lib/helper/ApiDataFactory.js +4 -7
  41. package/lib/helper/Appium.js +50 -57
  42. package/lib/helper/FileSystem.js +3 -3
  43. package/lib/helper/GraphQLDataFactory.js +4 -4
  44. package/lib/helper/JSONResponse.js +75 -37
  45. package/lib/helper/Mochawesome.js +31 -9
  46. package/lib/helper/Nightmare.js +37 -58
  47. package/lib/helper/Playwright.js +267 -272
  48. package/lib/helper/Protractor.js +56 -87
  49. package/lib/helper/Puppeteer.js +247 -264
  50. package/lib/helper/REST.js +29 -17
  51. package/lib/helper/TestCafe.js +22 -47
  52. package/lib/helper/WebDriver.js +157 -368
  53. package/lib/helper/extras/PlaywrightPropEngine.js +2 -2
  54. package/lib/helper/extras/Popup.js +22 -22
  55. package/lib/helper/network/utils.js +1 -1
  56. package/lib/helper/testcafe/testcafe-utils.js +27 -28
  57. package/lib/listener/emptyRun.js +55 -0
  58. package/lib/listener/exit.js +7 -10
  59. package/lib/listener/{retry.js → globalRetry.js} +5 -5
  60. package/lib/listener/globalTimeout.js +165 -0
  61. package/lib/listener/helpers.js +15 -15
  62. package/lib/listener/mocha.js +1 -1
  63. package/lib/listener/result.js +12 -0
  64. package/lib/listener/retryEnhancer.js +85 -0
  65. package/lib/listener/steps.js +32 -18
  66. package/lib/listener/store.js +20 -0
  67. package/lib/locator.js +1 -1
  68. package/lib/mocha/asyncWrapper.js +231 -0
  69. package/lib/{interfaces → mocha}/bdd.js +3 -3
  70. package/lib/mocha/cli.js +308 -0
  71. package/lib/mocha/factory.js +104 -0
  72. package/lib/{interfaces → mocha}/featureConfig.js +32 -12
  73. package/lib/{interfaces → mocha}/gherkin.js +26 -28
  74. package/lib/mocha/hooks.js +112 -0
  75. package/lib/mocha/index.js +12 -0
  76. package/lib/mocha/inject.js +29 -0
  77. package/lib/{interfaces → mocha}/scenarioConfig.js +31 -7
  78. package/lib/mocha/suite.js +82 -0
  79. package/lib/mocha/test.js +181 -0
  80. package/lib/mocha/types.d.ts +42 -0
  81. package/lib/mocha/ui.js +232 -0
  82. package/lib/output.js +93 -65
  83. package/lib/pause.js +160 -138
  84. package/lib/plugin/analyze.js +396 -0
  85. package/lib/plugin/auth.js +435 -0
  86. package/lib/plugin/autoDelay.js +8 -8
  87. package/lib/plugin/autoLogin.js +3 -338
  88. package/lib/plugin/commentStep.js +6 -1
  89. package/lib/plugin/coverage.js +10 -22
  90. package/lib/plugin/customLocator.js +3 -3
  91. package/lib/plugin/customReporter.js +52 -0
  92. package/lib/plugin/eachElement.js +1 -1
  93. package/lib/plugin/fakerTransform.js +1 -1
  94. package/lib/plugin/heal.js +36 -9
  95. package/lib/plugin/htmlReporter.js +1947 -0
  96. package/lib/plugin/pageInfo.js +140 -0
  97. package/lib/plugin/retryFailedStep.js +17 -18
  98. package/lib/plugin/retryTo.js +2 -113
  99. package/lib/plugin/screenshotOnFail.js +17 -58
  100. package/lib/plugin/selenoid.js +15 -35
  101. package/lib/plugin/standardActingHelpers.js +4 -1
  102. package/lib/plugin/stepByStepReport.js +56 -17
  103. package/lib/plugin/stepTimeout.js +5 -12
  104. package/lib/plugin/subtitles.js +4 -4
  105. package/lib/plugin/tryTo.js +3 -102
  106. package/lib/plugin/wdio.js +8 -10
  107. package/lib/recorder.js +155 -124
  108. package/lib/rerun.js +43 -42
  109. package/lib/result.js +161 -0
  110. package/lib/secret.js +1 -2
  111. package/lib/step/base.js +239 -0
  112. package/lib/step/comment.js +10 -0
  113. package/lib/step/config.js +50 -0
  114. package/lib/step/func.js +46 -0
  115. package/lib/step/helper.js +50 -0
  116. package/lib/step/meta.js +99 -0
  117. package/lib/step/record.js +74 -0
  118. package/lib/step/retry.js +11 -0
  119. package/lib/step/section.js +55 -0
  120. package/lib/step.js +21 -332
  121. package/lib/steps.js +50 -0
  122. package/lib/store.js +37 -5
  123. package/lib/template/heal.js +2 -11
  124. package/lib/test-server.js +323 -0
  125. package/lib/timeout.js +66 -0
  126. package/lib/utils.js +351 -218
  127. package/lib/within.js +75 -55
  128. package/lib/workerStorage.js +2 -1
  129. package/lib/workers.js +386 -277
  130. package/package.json +81 -75
  131. package/translations/de-DE.js +5 -3
  132. package/translations/fr-FR.js +5 -4
  133. package/translations/index.js +1 -0
  134. package/translations/it-IT.js +4 -3
  135. package/translations/ja-JP.js +4 -3
  136. package/translations/nl-NL.js +76 -0
  137. package/translations/pl-PL.js +4 -3
  138. package/translations/pt-BR.js +4 -3
  139. package/translations/ru-RU.js +4 -3
  140. package/translations/utils.js +9 -0
  141. package/translations/zh-CN.js +4 -3
  142. package/translations/zh-TW.js +4 -3
  143. package/typings/index.d.ts +197 -187
  144. package/typings/promiseBasedTypes.d.ts +53 -903
  145. package/typings/types.d.ts +372 -1042
  146. package/lib/cli.js +0 -257
  147. package/lib/helper/ExpectHelper.js +0 -391
  148. package/lib/helper/MockServer.js +0 -221
  149. package/lib/helper/SoftExpectHelper.js +0 -381
  150. package/lib/listener/artifacts.js +0 -19
  151. package/lib/listener/timeout.js +0 -109
  152. package/lib/mochaFactory.js +0 -113
  153. package/lib/plugin/debugErrors.js +0 -67
  154. package/lib/scenario.js +0 -224
  155. package/lib/ui.js +0 -236
@@ -7,19 +7,11 @@ const Helper = require('@codeceptjs/helper')
7
7
  const promiseRetry = require('promise-retry')
8
8
  const stringIncludes = require('../assert/include').includes
9
9
  const { urlEquals, equals } = require('../assert/equal')
10
+ const store = require('../store')
10
11
  const { debug } = require('../output')
11
12
  const { empty } = require('../assert/empty')
12
13
  const { truth } = require('../assert/truth')
13
- const {
14
- xpathLocator,
15
- fileExists,
16
- decodeUrl,
17
- chunkArray,
18
- convertCssPropertiesToCamelCase,
19
- screenshotOutputFolder,
20
- getNormalizedKeyAttributeValue,
21
- modifierKeys,
22
- } = require('../utils')
14
+ const { xpathLocator, fileExists, decodeUrl, chunkArray, convertCssPropertiesToCamelCase, screenshotOutputFolder, getNormalizedKeyAttributeValue, modifierKeys } = require('../utils')
23
15
  const { isColorProperty, convertColorToRGBA } = require('../colorUtils')
24
16
  const ElementNotFound = require('./errors/ElementNotFound')
25
17
  const ConnectionRefused = require('./errors/ConnectionRefused')
@@ -27,22 +19,13 @@ const Locator = require('../locator')
27
19
  const { highlightElement } = require('./scripts/highlightElement')
28
20
  const { focusElement } = require('./scripts/focusElement')
29
21
  const { blurElement } = require('./scripts/blurElement')
30
- const {
31
- dontSeeElementError,
32
- seeElementError,
33
- seeElementInDOMError,
34
- dontSeeElementInDOMError,
35
- } = require('./errors/ElementAssertion')
36
- const {
37
- dontSeeTraffic,
38
- seeTraffic,
39
- grabRecordedNetworkTraffics,
40
- stopRecordingTraffic,
41
- flushNetworkTraffics,
42
- } = require('./network/actions')
22
+ const { dontSeeElementError, seeElementError, seeElementInDOMError, dontSeeElementInDOMError } = require('./errors/ElementAssertion')
23
+ const { dontSeeTraffic, seeTraffic, grabRecordedNetworkTraffics, stopRecordingTraffic, flushNetworkTraffics } = require('./network/actions')
24
+ const WebElement = require('../element/WebElement')
43
25
 
44
26
  const SHADOW = 'shadow'
45
27
  const webRoot = 'body'
28
+ let browserLogs = []
46
29
 
47
30
  /**
48
31
  * ## Configuration
@@ -53,6 +36,7 @@ const webRoot = 'body'
53
36
  * @type {object}
54
37
  * @prop {string} url - base url of website to be tested.
55
38
  * @prop {string} browser - Browser in which to perform testing.
39
+ * @prop {boolean} [bidiProtocol=false] - WebDriver Bidi Protocol. Default: false. More info: https://webdriver.io/docs/api/webdriverBidi/
56
40
  * @prop {string} [basicAuth] - (optional) the basic authentication to pass to base url. Example: {username: 'username', password: 'password'}
57
41
  * @prop {string} [host=localhost] - WebDriver host to connect.
58
42
  * @prop {number} [port=4444] - WebDriver port to connect.
@@ -72,7 +56,6 @@ const webRoot = 'body'
72
56
  * @prop {object} [timeouts] [WebDriver timeouts](http://webdriver.io/docs/timeouts.html) defined as hash.
73
57
  * @prop {boolean} [highlightElement] - highlight the interacting elements. Default: false. Note: only activate under verbose mode (--verbose).
74
58
  * @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
75
- * @prop {boolean} [devtoolsProtocol=false] - enable devtools protocol. Default: false. More info: https://webdriver.io/docs/automationProtocols/#devtools-protocol.
76
59
  */
77
60
  const config = {}
78
61
 
@@ -180,7 +163,6 @@ const config = {}
180
163
  * WebDriver : {
181
164
  * url: "http://localhost",
182
165
  * browser: "chrome",
183
- * devtoolsProtocol: true,
184
166
  * desiredCapabilities: {
185
167
  * chromeOptions: {
186
168
  * args: [ "--headless", "--disable-gpu", "--no-sandbox" ]
@@ -508,6 +490,10 @@ class WebDriver extends Helper {
508
490
  config.capabilities = config.desiredCapabilities
509
491
  }
510
492
  config.capabilities.browserName = config.browser || config.capabilities.browserName
493
+
494
+ // WebDriver Bidi Protocol. Default: false
495
+ config.capabilities.webSocketUrl = config.bidiProtocol ?? config.capabilities.webSocketUrl ?? true
496
+
511
497
  config.capabilities.browserVersion = config.browserVersion || config.capabilities.browserVersion
512
498
  if (config.capabilities.chromeOptions) {
513
499
  config.capabilities['goog:chromeOptions'] = config.capabilities.chromeOptions
@@ -597,10 +583,7 @@ class WebDriver extends Helper {
597
583
  }
598
584
 
599
585
  async _res(locator) {
600
- const res =
601
- this._isShadowLocator(locator) || this._isCustomLocator(locator)
602
- ? await this._locate(locator)
603
- : await this.$$(withStrictLocator(locator))
586
+ const res = this._isShadowLocator(locator) || this._isCustomLocator(locator) ? await this._locate(locator) : await this.$$(withStrictLocator(locator))
604
587
  return res
605
588
  }
606
589
 
@@ -614,11 +597,6 @@ class WebDriver extends Helper {
614
597
  delete this.options.capabilities.hostname
615
598
  delete this.options.capabilities.port
616
599
  delete this.options.capabilities.path
617
- if (this.options.devtoolsProtocol) {
618
- if (!['chrome', 'chromium'].includes(this.options.browser.toLowerCase()))
619
- throw Error('The devtools protocol is only working with Chrome or Chromium')
620
- this.options.automationProtocol = 'devtools'
621
- }
622
600
  this.browser = await webdriverio.remote(this.options)
623
601
  }
624
602
  } catch (err) {
@@ -638,7 +616,7 @@ class WebDriver extends Helper {
638
616
  this.$$ = this.browser.$$.bind(this.browser)
639
617
 
640
618
  if (this._isCustomLocatorStrategyDefined()) {
641
- Object.keys(this.customLocatorStrategies).forEach(async (customLocator) => {
619
+ Object.keys(this.customLocatorStrategies).forEach(async customLocator => {
642
620
  this.debugSection('Weddriver', `adding custom locator strategy: ${customLocator}`)
643
621
  const locatorFunction = this._lookupCustomLocator(customLocator)
644
622
  this.browser.addLocatorStrategy(customLocator, locatorFunction)
@@ -649,10 +627,10 @@ class WebDriver extends Helper {
649
627
  this.browser.capabilities.platformName = this.browser.capabilities.platformName.toLowerCase()
650
628
  }
651
629
 
652
- if (this.options.automationProtocol) {
653
- this.puppeteerBrowser = await this.browser.getPuppeteer()
654
- this.page = (await this.puppeteerBrowser.pages())[0]
655
- }
630
+ this.browser.on('dialog', () => {})
631
+
632
+ await this.browser.sessionSubscribe({ events: ['log.entryAdded'] })
633
+ this.browser.on('log.entryAdded', logEvents)
656
634
 
657
635
  return this.browser
658
636
  }
@@ -679,7 +657,7 @@ class WebDriver extends Helper {
679
657
  this.isRunning = false
680
658
  return this.browser.deleteSession()
681
659
  }
682
- if (this.browser.isInsideFrame) await this.browser.switchToFrame(null)
660
+ if (this.browser.isInsideFrame) await this.browser.switchFrame(null)
683
661
 
684
662
  if (this.options.keepBrowserState) return
685
663
 
@@ -687,10 +665,11 @@ class WebDriver extends Helper {
687
665
  this.debugSection('Session', 'cleaning cookies and localStorage')
688
666
  await this.browser.deleteCookies()
689
667
  }
690
- await this.browser.execute('localStorage.clear();').catch((err) => {
668
+ await this.browser.execute('localStorage.clear();').catch(err => {
691
669
  if (!(err.message.indexOf("Storage is disabled inside 'data:' URLs.") > -1)) throw err
692
670
  })
693
671
  await this.closeOtherTabs()
672
+ browserLogs = []
694
673
  return this.browser
695
674
  }
696
675
 
@@ -717,17 +696,17 @@ class WebDriver extends Helper {
717
696
 
718
697
  return browser
719
698
  },
720
- stop: async (browser) => {
699
+ stop: async browser => {
721
700
  if (!browser) return
722
701
  return browser.deleteSession()
723
702
  },
724
- loadVars: async (browser) => {
703
+ loadVars: async browser => {
725
704
  if (this.context !== this.root) throw new Error("Can't start session inside within block")
726
705
  this.browser = browser
727
706
  this.$$ = this.browser.$$.bind(this.browser)
728
707
  this.sessionWindows[this.activeSessionName] = browser
729
708
  },
730
- restoreVars: async (session) => {
709
+ restoreVars: async session => {
731
710
  if (!session) {
732
711
  this.activeSessionName = ''
733
712
  }
@@ -769,7 +748,7 @@ class WebDriver extends Helper {
769
748
  this.browser.isInsideFrame = true
770
749
  if (Array.isArray(frame)) {
771
750
  // this.switchTo(null);
772
- await forEachAsync(frame, async (f) => this.switchTo(f))
751
+ await forEachAsync(frame, async f => this.switchTo(f))
773
752
  return
774
753
  }
775
754
  await this.switchTo(frame)
@@ -847,10 +826,7 @@ class WebDriver extends Helper {
847
826
  * @param {object} locator
848
827
  */
849
828
  async _smartWait(locator) {
850
- this.debugSection(
851
- `SmartWait (${this.options.smartWait}ms)`,
852
- `Locating ${JSON.stringify(locator)} in ${this.options.smartWait}`,
853
- )
829
+ this.debugSection(`SmartWait (${this.options.smartWait}ms)`, `Locating ${JSON.stringify(locator)} in ${this.options.smartWait}`)
854
830
  await this.defineTimeout({ implicit: this.options.smartWait })
855
831
  }
856
832
 
@@ -925,7 +901,7 @@ class WebDriver extends Helper {
925
901
  * @param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
926
902
  */
927
903
  async _locateCheckable(locator) {
928
- return findCheckable.call(this, locator, this.$$.bind(this)).then((res) => res)
904
+ return findCheckable.call(this, locator, this.$$.bind(this)).then(res => res)
929
905
  }
930
906
 
931
907
  /**
@@ -953,7 +929,7 @@ class WebDriver extends Helper {
953
929
  * @param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
954
930
  */
955
931
  async _locateFields(locator) {
956
- return findFields.call(this, locator).then((res) => res)
932
+ return findFields.call(this, locator).then(res => res)
957
933
  }
958
934
 
959
935
  /**
@@ -961,7 +937,20 @@ class WebDriver extends Helper {
961
937
  *
962
938
  */
963
939
  async grabWebElements(locator) {
964
- return this._locate(locator)
940
+ const elements = await this._locate(locator)
941
+ return elements.map(element => new WebElement(element, this))
942
+ }
943
+
944
+ /**
945
+ * {{> grabWebElement }}
946
+ *
947
+ */
948
+ async grabWebElement(locator) {
949
+ const elements = await this._locate(locator)
950
+ if (elements.length === 0) {
951
+ throw new ElementNotFound(locator, 'Element')
952
+ }
953
+ return new WebElement(elements[0], this)
965
954
  }
966
955
 
967
956
  /**
@@ -1037,7 +1026,7 @@ class WebDriver extends Helper {
1037
1026
  const elem = usingFirstElement(res)
1038
1027
  highlightActiveElement.call(this, elem)
1039
1028
 
1040
- return this.executeScript((el) => {
1029
+ return this.executeScript(el => {
1041
1030
  if (document.activeElement instanceof HTMLElement) {
1042
1031
  document.activeElement.blur()
1043
1032
  }
@@ -1109,7 +1098,7 @@ class WebDriver extends Helper {
1109
1098
  }
1110
1099
  const elem = usingFirstElement(res)
1111
1100
 
1112
- return this.executeScript((el) => {
1101
+ return this.executeScript(el => {
1113
1102
  if (document.activeElement instanceof HTMLElement) {
1114
1103
  document.activeElement.blur()
1115
1104
  }
@@ -1143,10 +1132,6 @@ class WebDriver extends Helper {
1143
1132
  assertElementExists(res, field, 'Field')
1144
1133
  const elem = usingFirstElement(res)
1145
1134
  highlightActiveElement.call(this, elem)
1146
- if (this.options.automationProtocol) {
1147
- const curentValue = await elem.getValue()
1148
- return elem.setValue(curentValue + value.toString())
1149
- }
1150
1135
  return elem.addValue(value.toString())
1151
1136
  }
1152
1137
 
@@ -1159,9 +1144,6 @@ class WebDriver extends Helper {
1159
1144
  assertElementExists(res, field, 'Field')
1160
1145
  const elem = usingFirstElement(res)
1161
1146
  highlightActiveElement.call(this, elem)
1162
- if (this.options.automationProtocol) {
1163
- return elem.setValue('')
1164
- }
1165
1147
  return elem.clearValue(getElementId(elem))
1166
1148
  }
1167
1149
 
@@ -1179,15 +1161,9 @@ class WebDriver extends Helper {
1179
1161
  }
1180
1162
 
1181
1163
  // select options by visible text
1182
- let els = await forEachAsync(option, async (opt) =>
1183
- this.browser.findElementsFromElement(
1184
- getElementId(elem),
1185
- 'xpath',
1186
- Locator.select.byVisibleText(xpathLocator.literal(opt)),
1187
- ),
1188
- )
1164
+ let els = await forEachAsync(option, async opt => this.browser.findElementsFromElement(getElementId(elem), 'xpath', Locator.select.byVisibleText(xpathLocator.literal(opt))))
1189
1165
 
1190
- const clickOptionFn = async (el) => {
1166
+ const clickOptionFn = async el => {
1191
1167
  if (el[0]) el = el[0]
1192
1168
  const elementId = getElementId(el)
1193
1169
  if (elementId) return this.browser.elementClick(elementId)
@@ -1197,19 +1173,9 @@ class WebDriver extends Helper {
1197
1173
  return forEachAsync(els, clickOptionFn)
1198
1174
  }
1199
1175
  // select options by value
1200
- els = await forEachAsync(option, async (opt) =>
1201
- this.browser.findElementsFromElement(
1202
- getElementId(elem),
1203
- 'xpath',
1204
- Locator.select.byValue(xpathLocator.literal(opt)),
1205
- ),
1206
- )
1176
+ els = await forEachAsync(option, async opt => this.browser.findElementsFromElement(getElementId(elem), 'xpath', Locator.select.byValue(xpathLocator.literal(opt))))
1207
1177
  if (els.length === 0) {
1208
- throw new ElementNotFound(
1209
- select,
1210
- `Option "${option}" in`,
1211
- 'was not found neither by a visible text nor by a value',
1212
- )
1178
+ throw new ElementNotFound(select, `Option "${option}" in`, 'was not found neither by a visible text nor by a value')
1213
1179
  }
1214
1180
  return forEachAsync(els, clickOptionFn)
1215
1181
  }
@@ -1231,14 +1197,12 @@ class WebDriver extends Helper {
1231
1197
  const el = usingFirstElement(res)
1232
1198
 
1233
1199
  // Remote Upload (when running Selenium Server)
1234
- if (this.options.remoteFileUpload && !this.options.automationProtocol) {
1200
+ if (this.options.remoteFileUpload) {
1235
1201
  try {
1236
1202
  this.debugSection('File', 'Uploading file to remote server')
1237
1203
  file = await this.browser.uploadFile(file)
1238
1204
  } catch (err) {
1239
- throw new Error(
1240
- `File can't be transferred to remote server. Set \`remoteFileUpload: false\` in config to upload file locally.\n${err.message}`,
1241
- )
1205
+ throw new Error(`File can't be transferred to remote server. Set \`remoteFileUpload: false\` in config to upload file locally.\n${err.message}`)
1242
1206
  }
1243
1207
  }
1244
1208
 
@@ -1291,7 +1255,11 @@ class WebDriver extends Helper {
1291
1255
  */
1292
1256
  async grabTextFromAll(locator) {
1293
1257
  const res = await this._locate(locator, true)
1294
- const val = await forEachAsync(res, (el) => this.browser.getElementText(getElementId(el)))
1258
+ let val = []
1259
+ await forEachAsync(res, async el => {
1260
+ const text = await this.browser.getElementText(getElementId(el))
1261
+ val.push(text)
1262
+ })
1295
1263
  this.debugSection('GrabText', String(val))
1296
1264
  return val
1297
1265
  }
@@ -1316,7 +1284,7 @@ class WebDriver extends Helper {
1316
1284
  */
1317
1285
  async grabHTMLFromAll(locator) {
1318
1286
  const elems = await this._locate(locator, true)
1319
- const html = await forEachAsync(elems, (elem) => elem.getHTML(false))
1287
+ const html = await forEachAsync(elems, elem => elem.getHTML(false))
1320
1288
  this.debugSection('GrabHTML', String(html))
1321
1289
  return html
1322
1290
  }
@@ -1341,7 +1309,7 @@ class WebDriver extends Helper {
1341
1309
  */
1342
1310
  async grabValueFromAll(locator) {
1343
1311
  const res = await this._locate(locator, true)
1344
- const val = await forEachAsync(res, (el) => el.getValue())
1312
+ const val = await forEachAsync(res, el => el.getValue())
1345
1313
  this.debugSection('GrabValue', String(val))
1346
1314
 
1347
1315
  return val
@@ -1366,7 +1334,7 @@ class WebDriver extends Helper {
1366
1334
  */
1367
1335
  async grabCssPropertyFromAll(locator, cssProperty) {
1368
1336
  const res = await this._locate(locator, true)
1369
- const val = await forEachAsync(res, async (el) => this.browser.getElementCSSValue(getElementId(el), cssProperty))
1337
+ const val = await forEachAsync(res, async el => this.browser.getElementCSSValue(getElementId(el), cssProperty))
1370
1338
  this.debugSection('Grab', String(val))
1371
1339
  return val
1372
1340
  }
@@ -1390,7 +1358,7 @@ class WebDriver extends Helper {
1390
1358
  */
1391
1359
  async grabAttributeFromAll(locator, attr) {
1392
1360
  const res = await this._locate(locator, true)
1393
- const val = await forEachAsync(res, async (el) => el.getAttribute(attr))
1361
+ const val = await forEachAsync(res, async el => el.getAttribute(attr))
1394
1362
  this.debugSection('GrabAttribute', String(val))
1395
1363
  return val
1396
1364
  }
@@ -1507,7 +1475,7 @@ class WebDriver extends Helper {
1507
1475
  async seeElement(locator) {
1508
1476
  const res = await this._locate(locator, true)
1509
1477
  assertElementExists(res, locator)
1510
- const selected = await forEachAsync(res, async (el) => el.isDisplayed())
1478
+ const selected = await forEachAsync(res, async el => el.isDisplayed())
1511
1479
  try {
1512
1480
  return truth(`elements of ${new Locator(locator)}`, 'to be seen').assert(selected)
1513
1481
  } catch (e) {
@@ -1524,7 +1492,7 @@ class WebDriver extends Helper {
1524
1492
  if (!res || res.length === 0) {
1525
1493
  return truth(`elements of ${new Locator(locator)}`, 'to be seen').negate(false)
1526
1494
  }
1527
- const selected = await forEachAsync(res, async (el) => el.isDisplayed())
1495
+ const selected = await forEachAsync(res, async el => el.isDisplayed())
1528
1496
  try {
1529
1497
  return truth(`elements of ${new Locator(locator)}`, 'to be seen').negate(selected)
1530
1498
  } catch (e) {
@@ -1579,11 +1547,7 @@ class WebDriver extends Helper {
1579
1547
  * {{> grabBrowserLogs }}
1580
1548
  */
1581
1549
  async grabBrowserLogs() {
1582
- if (this.browser.isW3C) {
1583
- this.debug('Logs not available in W3C specification')
1584
- return
1585
- }
1586
- return this.browser.getLogs('browser')
1550
+ return browserLogs
1587
1551
  }
1588
1552
 
1589
1553
  /**
@@ -1609,11 +1573,7 @@ class WebDriver extends Helper {
1609
1573
  */
1610
1574
  async seeNumberOfElements(locator, num) {
1611
1575
  const res = await this._locate(locator)
1612
- return assert.equal(
1613
- res.length,
1614
- num,
1615
- `expected number of elements (${new Locator(locator)}) is ${num}, but found ${res.length}`,
1616
- )
1576
+ return assert.equal(res.length, num, `expected number of elements (${new Locator(locator)}) is ${num}, but found ${res.length}`)
1617
1577
  }
1618
1578
 
1619
1579
  /**
@@ -1622,11 +1582,7 @@ class WebDriver extends Helper {
1622
1582
  */
1623
1583
  async seeNumberOfVisibleElements(locator, num) {
1624
1584
  const res = await this.grabNumberOfVisibleElements(locator)
1625
- return assert.equal(
1626
- res,
1627
- num,
1628
- `expected number of visible elements (${new Locator(locator)}) is ${num}, but found ${res}`,
1629
- )
1585
+ return assert.equal(res, num, `expected number of visible elements (${new Locator(locator)}) is ${num}, but found ${res}`)
1630
1586
  }
1631
1587
 
1632
1588
  /**
@@ -1651,19 +1607,16 @@ class WebDriver extends Helper {
1651
1607
  }
1652
1608
  }
1653
1609
 
1654
- const values = Object.keys(cssPropertiesCamelCase).map((key) => cssPropertiesCamelCase[key])
1610
+ const values = Object.keys(cssPropertiesCamelCase).map(key => cssPropertiesCamelCase[key])
1655
1611
  if (!Array.isArray(props)) props = [props]
1656
1612
  let chunked = chunkArray(props, values.length)
1657
- chunked = chunked.filter((val) => {
1613
+ chunked = chunked.filter(val => {
1658
1614
  for (let i = 0; i < val.length; ++i) {
1659
- // eslint-disable-next-line eqeqeq
1660
1615
  if (val[i] != values[i]) return false
1661
1616
  }
1662
1617
  return true
1663
1618
  })
1664
- return equals(
1665
- `all elements (${new Locator(locator)}) to have CSS property ${JSON.stringify(cssProperties)}`,
1666
- ).assert(chunked.length, elemAmount)
1619
+ return equals(`all elements (${new Locator(locator)}) to have CSS property ${JSON.stringify(cssProperties)}`).assert(chunked.length, elemAmount)
1667
1620
  }
1668
1621
 
1669
1622
  /**
@@ -1674,28 +1627,24 @@ class WebDriver extends Helper {
1674
1627
  assertElementExists(res, locator)
1675
1628
  const elemAmount = res.length
1676
1629
 
1677
- let attrs = await forEachAsync(res, async (el) => {
1678
- return forEachAsync(Object.keys(attributes), async (attr) => el.getAttribute(attr))
1630
+ let attrs = await forEachAsync(res, async el => {
1631
+ return forEachAsync(Object.keys(attributes), async attr => el.getAttribute(attr))
1679
1632
  })
1680
1633
 
1681
- const values = Object.keys(attributes).map((key) => attributes[key])
1634
+ const values = Object.keys(attributes).map(key => attributes[key])
1682
1635
  if (!Array.isArray(attrs)) attrs = [attrs]
1683
1636
  let chunked = chunkArray(attrs, values.length)
1684
- chunked = chunked.filter((val) => {
1637
+ chunked = chunked.filter(val => {
1685
1638
  for (let i = 0; i < val.length; ++i) {
1686
1639
  const _actual = Number.isNaN(val[i]) || typeof values[i] === 'string' ? val[i] : Number.parseInt(val[i], 10)
1687
- const _expected =
1688
- Number.isNaN(values[i]) || typeof values[i] === 'string' ? values[i] : Number.parseInt(values[i], 10)
1640
+ const _expected = Number.isNaN(values[i]) || typeof values[i] === 'string' ? values[i] : Number.parseInt(values[i], 10)
1689
1641
  // the attribute could be a boolean
1690
1642
  if (typeof _actual === 'boolean') return _actual === _expected
1691
1643
  if (_actual !== _expected) return false
1692
1644
  }
1693
1645
  return true
1694
1646
  })
1695
- return assert.ok(
1696
- chunked.length === elemAmount,
1697
- `expected all elements (${new Locator(locator)}) to have attributes ${JSON.stringify(attributes)}`,
1698
- )
1647
+ return assert.ok(chunked.length === elemAmount, `expected all elements (${new Locator(locator)}) to have attributes ${JSON.stringify(attributes)}`)
1699
1648
  }
1700
1649
 
1701
1650
  /**
@@ -1704,9 +1653,9 @@ class WebDriver extends Helper {
1704
1653
  async grabNumberOfVisibleElements(locator) {
1705
1654
  const res = await this._locate(locator)
1706
1655
 
1707
- let selected = await forEachAsync(res, async (el) => el.isDisplayed())
1656
+ let selected = await forEachAsync(res, async el => el.isDisplayed())
1708
1657
  if (!Array.isArray(selected)) selected = [selected]
1709
- selected = selected.filter((val) => val === true)
1658
+ selected = selected.filter(val => val === true)
1710
1659
  return selected.length
1711
1660
  }
1712
1661
 
@@ -1793,7 +1742,7 @@ class WebDriver extends Helper {
1793
1742
  if (this.browser.isMobile && !this.browser.isW3C) return this.browser.touchScroll(offsetX, offsetY, elementId)
1794
1743
  const location = await elem.getLocation()
1795
1744
  assertElementExists(location, locator, 'Failed to receive', 'location')
1796
- /* eslint-disable prefer-arrow-callback */
1745
+
1797
1746
  return this.browser.execute(
1798
1747
  function (x, y) {
1799
1748
  return window.scrollTo(x, y)
@@ -1801,12 +1750,10 @@ class WebDriver extends Helper {
1801
1750
  location.x + offsetX,
1802
1751
  location.y + offsetY,
1803
1752
  )
1804
- /* eslint-enable */
1805
1753
  }
1806
1754
 
1807
1755
  if (this.browser.isMobile && !this.browser.isW3C) return this.browser.touchScroll(locator, offsetX, offsetY)
1808
1756
 
1809
- /* eslint-disable prefer-arrow-callback, comma-dangle */
1810
1757
  return this.browser.execute(
1811
1758
  function (x, y) {
1812
1759
  return window.scrollTo(x, y)
@@ -1814,7 +1761,6 @@ class WebDriver extends Helper {
1814
1761
  offsetX,
1815
1762
  offsetY,
1816
1763
  )
1817
- /* eslint-enable */
1818
1764
  }
1819
1765
 
1820
1766
  /**
@@ -1863,19 +1809,25 @@ class WebDriver extends Helper {
1863
1809
 
1864
1810
  if (browser) {
1865
1811
  this.debug(`Screenshot of ${sessionName} session has been saved to ${outputFile}`)
1866
- return browser.saveScreenshot(outputFile)
1812
+ await browser.saveScreenshot(outputFile)
1867
1813
  }
1868
1814
  }
1869
1815
  }
1870
1816
 
1871
1817
  if (!fullPage) {
1872
1818
  this.debug(`Screenshot has been saved to ${outputFile}`)
1873
- return this.browser.saveScreenshot(outputFile)
1819
+ await this.browser.saveScreenshot(outputFile)
1874
1820
  }
1875
1821
 
1876
- /* eslint-disable prefer-arrow-callback, comma-dangle, prefer-const */
1877
1822
  const originalWindowSize = await this.browser.getWindowSize()
1878
1823
 
1824
+ // this case running on device, so we could not set the windowSize
1825
+ if (this.browser.isMobile) {
1826
+ this.debug(`Screenshot has been saved to ${outputFile}, size: ${originalWindowSize.width}x${originalWindowSize.height}`)
1827
+ const buffer = await this.browser.saveScreenshot(outputFile)
1828
+ return buffer
1829
+ }
1830
+
1879
1831
  let { width, height } = await this.browser
1880
1832
  .execute(function () {
1881
1833
  return {
@@ -1883,10 +1835,9 @@ class WebDriver extends Helper {
1883
1835
  width: document.body.scrollWidth,
1884
1836
  }
1885
1837
  })
1886
- .then((res) => res)
1838
+ .then(res => res)
1887
1839
 
1888
1840
  if (height < 100) height = 500 // errors for very small height
1889
- /* eslint-enable */
1890
1841
 
1891
1842
  await this.browser.setWindowSize(width, height)
1892
1843
  this.debug(`Screenshot has been saved to ${outputFile}, size: ${width}x${height}`)
@@ -1952,7 +1903,7 @@ class WebDriver extends Helper {
1952
1903
 
1953
1904
  return promiseRetry(
1954
1905
  async (retry, number) => {
1955
- const _grabCookie = async (name) => {
1906
+ const _grabCookie = async name => {
1956
1907
  const cookie = await this.browser.getCookies([name])
1957
1908
  if (cookie.length === 0) throw Error(`Cookie ${name} is not found after ${retries}s`)
1958
1909
  }
@@ -1976,11 +1927,10 @@ class WebDriver extends Helper {
1976
1927
  * libraries](http://jster.net/category/windows-modals-popups).
1977
1928
  */
1978
1929
  async acceptPopup() {
1979
- return this.browser.getAlertText().then((res) => {
1980
- if (res !== null) {
1981
- return this.browser.acceptAlert()
1982
- }
1983
- })
1930
+ const text = await this.browser.getAlertText()
1931
+ if (text) {
1932
+ return await this.browser.acceptAlert()
1933
+ }
1984
1934
  }
1985
1935
 
1986
1936
  /**
@@ -1988,11 +1938,10 @@ class WebDriver extends Helper {
1988
1938
  *
1989
1939
  */
1990
1940
  async cancelPopup() {
1991
- return this.browser.getAlertText().then((res) => {
1992
- if (res !== null) {
1993
- return this.browser.dismissAlert()
1994
- }
1995
- })
1941
+ const text = await this.browser.getAlertText()
1942
+ if (text) {
1943
+ return await this.browser.dismissAlert()
1944
+ }
1996
1945
  }
1997
1946
 
1998
1947
  /**
@@ -2002,7 +1951,7 @@ class WebDriver extends Helper {
2002
1951
  * @param {string} text value to check.
2003
1952
  */
2004
1953
  async seeInPopup(text) {
2005
- return this.browser.getAlertText().then((res) => {
1954
+ return await this.browser.getAlertText().then(res => {
2006
1955
  if (res === null) {
2007
1956
  throw new Error('Popup is not opened')
2008
1957
  }
@@ -2283,9 +2232,9 @@ class WebDriver extends Helper {
2283
2232
  async closeOtherTabs() {
2284
2233
  const handles = await this.browser.getWindowHandles()
2285
2234
  const currentHandle = await this.browser.getWindowHandle()
2286
- const otherHandles = handles.filter((handle) => handle !== currentHandle)
2235
+ const otherHandles = handles.filter(handle => handle !== currentHandle)
2287
2236
 
2288
- await forEachAsync(otherHandles, async (handle) => {
2237
+ await forEachAsync(otherHandles, async handle => {
2289
2238
  await this.browser.switchToWindow(handle)
2290
2239
  await this.browser.closeWindow()
2291
2240
  })
@@ -2296,7 +2245,7 @@ class WebDriver extends Helper {
2296
2245
  * {{> wait }}
2297
2246
  */
2298
2247
  async wait(sec) {
2299
- return new Promise((resolve) => {
2248
+ return new Promise(resolve => {
2300
2249
  setTimeout(resolve, sec * 1000)
2301
2250
  })
2302
2251
  }
@@ -2313,9 +2262,9 @@ class WebDriver extends Helper {
2313
2262
  if (!res || res.length === 0) {
2314
2263
  return false
2315
2264
  }
2316
- const selected = await forEachAsync(res, async (el) => this.browser.isElementEnabled(getElementId(el)))
2265
+ const selected = await forEachAsync(res, async el => this.browser.isElementEnabled(getElementId(el)))
2317
2266
  if (Array.isArray(selected)) {
2318
- return selected.filter((val) => val === true).length > 0
2267
+ return selected.filter(val => val === true).length > 0
2319
2268
  }
2320
2269
  return selected
2321
2270
  },
@@ -2370,14 +2319,14 @@ class WebDriver extends Helper {
2370
2319
  return client
2371
2320
  .waitUntil(
2372
2321
  function () {
2373
- return this.getUrl().then((res) => {
2322
+ return this.getUrl().then(res => {
2374
2323
  currUrl = decodeUrl(res)
2375
2324
  return currUrl.indexOf(urlPart) > -1
2376
2325
  })
2377
2326
  },
2378
2327
  { timeout: aSec * 1000 },
2379
2328
  )
2380
- .catch((e) => {
2329
+ .catch(e => {
2381
2330
  if (e.message.indexOf('timeout')) {
2382
2331
  throw new Error(`expected url to include ${urlPart}, but found ${currUrl}`)
2383
2332
  }
@@ -2397,12 +2346,12 @@ class WebDriver extends Helper {
2397
2346
  let currUrl = ''
2398
2347
  return this.browser
2399
2348
  .waitUntil(function () {
2400
- return this.getUrl().then((res) => {
2349
+ return this.getUrl().then(res => {
2401
2350
  currUrl = decodeUrl(res)
2402
2351
  return currUrl === urlPart
2403
2352
  })
2404
2353
  }, aSec * 1000)
2405
- .catch((e) => {
2354
+ .catch(e => {
2406
2355
  if (e.message.indexOf('timeout')) {
2407
2356
  throw new Error(`expected url to be ${urlPart}, but found ${currUrl}`)
2408
2357
  }
@@ -2422,9 +2371,9 @@ class WebDriver extends Helper {
2422
2371
  async () => {
2423
2372
  const res = await this.$$(withStrictLocator.call(this, _context))
2424
2373
  if (!res || res.length === 0) return false
2425
- const selected = await forEachAsync(res, async (el) => this.browser.getElementText(getElementId(el)))
2374
+ const selected = await forEachAsync(res, async el => this.browser.getElementText(getElementId(el)))
2426
2375
  if (Array.isArray(selected)) {
2427
- return selected.filter((part) => part.indexOf(text) >= 0).length > 0
2376
+ return selected.filter(part => part.indexOf(text) >= 0).length > 0
2428
2377
  }
2429
2378
  return selected.indexOf(text) >= 0
2430
2379
  },
@@ -2446,9 +2395,9 @@ class WebDriver extends Helper {
2446
2395
  async () => {
2447
2396
  const res = await findFields.call(this, field)
2448
2397
  if (!res || res.length === 0) return false
2449
- const selected = await forEachAsync(res, async (el) => el.getValue())
2398
+ const selected = await forEachAsync(res, async el => el.getValue())
2450
2399
  if (Array.isArray(selected)) {
2451
- return selected.filter((part) => part.indexOf(value) >= 0).length > 0
2400
+ return selected.filter(part => part.indexOf(value) >= 0).length > 0
2452
2401
  }
2453
2402
  return selected.indexOf(value) >= 0
2454
2403
  },
@@ -2470,9 +2419,9 @@ class WebDriver extends Helper {
2470
2419
  async () => {
2471
2420
  const res = await this._res(locator)
2472
2421
  if (!res || res.length === 0) return false
2473
- const selected = await forEachAsync(res, async (el) => el.isDisplayed())
2422
+ const selected = await forEachAsync(res, async el => el.isDisplayed())
2474
2423
  if (Array.isArray(selected)) {
2475
- return selected.filter((val) => val === true).length > 0
2424
+ return selected.filter(val => val === true).length > 0
2476
2425
  }
2477
2426
  return selected
2478
2427
  },
@@ -2493,10 +2442,10 @@ class WebDriver extends Helper {
2493
2442
  async () => {
2494
2443
  const res = await this._res(locator)
2495
2444
  if (!res || res.length === 0) return false
2496
- let selected = await forEachAsync(res, async (el) => el.isDisplayed())
2445
+ let selected = await forEachAsync(res, async el => el.isDisplayed())
2497
2446
 
2498
2447
  if (!Array.isArray(selected)) selected = [selected]
2499
- selected = selected.filter((val) => val === true)
2448
+ selected = selected.filter(val => val === true)
2500
2449
  return selected.length === num
2501
2450
  },
2502
2451
  {
@@ -2516,7 +2465,7 @@ class WebDriver extends Helper {
2516
2465
  async () => {
2517
2466
  const res = await this._res(locator)
2518
2467
  if (!res || res.length === 0) return true
2519
- const selected = await forEachAsync(res, async (el) => el.isDisplayed())
2468
+ const selected = await forEachAsync(res, async el => el.isDisplayed())
2520
2469
  return !selected.length
2521
2470
  },
2522
2471
  { timeout: aSec * 1000, timeoutMsg: `element (${new Locator(locator)}) still visible after ${aSec} sec` },
@@ -2592,20 +2541,14 @@ class WebDriver extends Helper {
2592
2541
  */
2593
2542
  async switchTo(locator) {
2594
2543
  this.browser.isInsideFrame = true
2595
- if (Number.isInteger(locator)) {
2596
- if (this.options.automationProtocol) {
2597
- return this.browser.switchToFrame(locator + 1)
2598
- }
2599
- return this.browser.switchToFrame(locator)
2600
- }
2601
2544
  if (!locator) {
2602
- return this.browser.switchToFrame(null)
2545
+ return this.browser.switchFrame(null)
2603
2546
  }
2604
2547
 
2605
2548
  let res = await this._locate(locator, true)
2606
2549
  assertElementExists(res, locator)
2607
2550
  res = usingFirstElement(res)
2608
- return this.browser.switchToFrame(res)
2551
+ return this.browser.switchFrame(res)
2609
2552
  }
2610
2553
 
2611
2554
  /**
@@ -2618,7 +2561,7 @@ class WebDriver extends Helper {
2618
2561
 
2619
2562
  await this.browser.waitUntil(
2620
2563
  async () => {
2621
- await this.browser.getWindowHandles().then((handles) => {
2564
+ await this.browser.getWindowHandles().then(handles => {
2622
2565
  if (handles.indexOf(current) + num + 1 <= handles.length) {
2623
2566
  target = handles[handles.indexOf(current) + num]
2624
2567
  }
@@ -2640,7 +2583,7 @@ class WebDriver extends Helper {
2640
2583
 
2641
2584
  await this.browser.waitUntil(
2642
2585
  async () => {
2643
- await this.browser.getWindowHandles().then((handles) => {
2586
+ await this.browser.getWindowHandles().then(handles => {
2644
2587
  if (handles.indexOf(current) - num > -1) {
2645
2588
  target = handles[handles.indexOf(current) - num]
2646
2589
  }
@@ -2695,11 +2638,10 @@ class WebDriver extends Helper {
2695
2638
  */
2696
2639
  scrollPageToTop() {
2697
2640
  const client = this.browser
2698
- /* eslint-disable prefer-arrow-callback */
2641
+
2699
2642
  return client.execute(function () {
2700
2643
  window.scrollTo(0, 0)
2701
2644
  })
2702
- /* eslint-enable */
2703
2645
  }
2704
2646
 
2705
2647
  /**
@@ -2707,69 +2649,26 @@ class WebDriver extends Helper {
2707
2649
  */
2708
2650
  scrollPageToBottom() {
2709
2651
  const client = this.browser
2710
- /* eslint-disable prefer-arrow-callback, comma-dangle */
2652
+
2711
2653
  return client.execute(function () {
2712
2654
  const body = document.body
2713
2655
  const html = document.documentElement
2714
- window.scrollTo(
2715
- 0,
2716
- Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight),
2717
- )
2656
+ window.scrollTo(0, Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight))
2718
2657
  })
2719
- /* eslint-enable */
2720
2658
  }
2721
2659
 
2722
2660
  /**
2723
2661
  * {{> grabPageScrollPosition }}
2724
2662
  */
2725
2663
  async grabPageScrollPosition() {
2726
- /* eslint-disable comma-dangle */
2727
2664
  function getScrollPosition() {
2728
2665
  return {
2729
2666
  x: window.pageXOffset,
2730
2667
  y: window.pageYOffset,
2731
2668
  }
2732
2669
  }
2733
- /* eslint-enable comma-dangle */
2734
- return this.executeScript(getScrollPosition)
2735
- }
2736
-
2737
- /**
2738
- * This method is **deprecated**.
2739
- *
2740
- *
2741
- * {{> setGeoLocation }}
2742
- */
2743
- async setGeoLocation(latitude, longitude) {
2744
- if (!this.options.automationProtocol) {
2745
- console.log(`setGeoLocation deprecated:
2746
- * This command is deprecated due to using deprecated JSON Wire Protocol command. More info: https://webdriver.io/docs/api/jsonwp/#setgeolocation
2747
- * Switch to devtools protocol to use this command by setting devtoolsProtocol: true in the configuration`)
2748
- return
2749
- }
2750
- this.geoLocation = { latitude, longitude }
2751
-
2752
- await this.browser.call(async () => {
2753
- const pages = await this.puppeteerBrowser.pages()
2754
- await pages[0].setGeolocation({ latitude, longitude })
2755
- })
2756
- }
2757
2670
 
2758
- /**
2759
- * This method is **deprecated**.
2760
- *
2761
- * {{> grabGeoLocation }}
2762
- *
2763
- */
2764
- async grabGeoLocation() {
2765
- if (!this.options.automationProtocol) {
2766
- console.log(`grabGeoLocation deprecated:
2767
- * This command is deprecated due to using deprecated JSON Wire Protocol command. More info: https://webdriver.io/docs/api/jsonwp/#getgeolocation
2768
- * Switch to devtools protocol to use this command by setting devtoolsProtocol: true in the configuration`)
2769
- return
2770
- }
2771
- if (!this.geoLocation) return 'No GeoLocation is set!'
2772
- return this.geoLocation
2671
+ return this.executeScript(getScrollPosition)
2773
2672
  }
2774
2673
 
2775
2674
  /**
@@ -2793,7 +2692,7 @@ class WebDriver extends Helper {
2793
2692
  * @param {*} caps
2794
2693
  * @param {*} fn
2795
2694
  */
2796
- /* eslint-disable */
2695
+
2797
2696
  runOnIOS(caps, fn) {}
2798
2697
 
2799
2698
  /**
@@ -2802,135 +2701,13 @@ class WebDriver extends Helper {
2802
2701
  * @param {*} fn
2803
2702
  */
2804
2703
  runOnAndroid(caps, fn) {}
2805
- /* eslint-enable */
2806
2704
 
2807
2705
  /**
2808
2706
  * Placeholder for ~ locator only test case write once run on both Appium and WebDriver.
2809
2707
  */
2810
- runInWeb(fn) {
2708
+ async runInWeb(fn) {
2811
2709
  return fn()
2812
2710
  }
2813
-
2814
- /**
2815
- *
2816
- * _Note:_ Only works when devtoolsProtocol is enabled.
2817
- *
2818
- * {{> flushNetworkTraffics }}
2819
- */
2820
- flushNetworkTraffics() {
2821
- if (!this.options.automationProtocol) {
2822
- console.log(
2823
- '* Switch to devtools protocol to use this command by setting devtoolsProtocol: true in the configuration',
2824
- )
2825
- return
2826
- }
2827
- this.requests = []
2828
- }
2829
-
2830
- /**
2831
- *
2832
- * _Note:_ Only works when devtoolsProtocol is enabled.
2833
- *
2834
- * {{> stopRecordingTraffic }}
2835
- */
2836
- stopRecordingTraffic() {
2837
- if (!this.options.automationProtocol) {
2838
- console.log(
2839
- '* Switch to devtools protocol to use this command by setting devtoolsProtocol: true in the configuration',
2840
- )
2841
- return
2842
- }
2843
- this.page.removeAllListeners('request')
2844
- this.recording = false
2845
- }
2846
-
2847
- /**
2848
- *
2849
- * _Note:_ Only works when devtoolsProtocol is enabled.
2850
- *
2851
- * {{> startRecordingTraffic }}
2852
- *
2853
- */
2854
- async startRecordingTraffic() {
2855
- if (!this.options.automationProtocol) {
2856
- console.log(
2857
- '* Switch to devtools protocol to use this command by setting devtoolsProtocol: true in the configuration',
2858
- )
2859
- return
2860
- }
2861
- this.flushNetworkTraffics()
2862
- this.recording = true
2863
- this.recordedAtLeastOnce = true
2864
-
2865
- await this.page.setRequestInterception(true)
2866
-
2867
- this.page.on('request', (request) => {
2868
- const information = {
2869
- url: request.url(),
2870
- method: request.method(),
2871
- requestHeaders: request.headers(),
2872
- requestPostData: request.postData(),
2873
- response: request.response(),
2874
- }
2875
-
2876
- this.debugSection('REQUEST: ', JSON.stringify(information))
2877
-
2878
- if (typeof information.requestPostData === 'object') {
2879
- information.requestPostData = JSON.parse(information.requestPostData)
2880
- }
2881
- request.continue()
2882
- this.requests.push(information)
2883
- })
2884
- }
2885
-
2886
- /**
2887
- *
2888
- * _Note:_ Only works when devtoolsProtocol is enabled.
2889
- *
2890
- * {{> grabRecordedNetworkTraffics }}
2891
- */
2892
- async grabRecordedNetworkTraffics() {
2893
- if (!this.options.automationProtocol) {
2894
- console.log(
2895
- '* Switch to devtools protocol to use this command by setting devtoolsProtocol: true in the configuration',
2896
- )
2897
- return
2898
- }
2899
- return grabRecordedNetworkTraffics.call(this)
2900
- }
2901
-
2902
- /**
2903
- *
2904
- * _Note:_ Only works when devtoolsProtocol is enabled.
2905
- *
2906
- * {{> seeTraffic }}
2907
- */
2908
- async seeTraffic({ name, url, parameters, requestPostData, timeout = 10 }) {
2909
- if (!this.options.automationProtocol) {
2910
- console.log(
2911
- '* Switch to devtools protocol to use this command by setting devtoolsProtocol: true in the configuration',
2912
- )
2913
- return
2914
- }
2915
- await seeTraffic.call(this, ...arguments)
2916
- }
2917
-
2918
- /**
2919
- *
2920
- * _Note:_ Only works when devtoolsProtocol is enabled.
2921
- *
2922
- * {{> dontSeeTraffic }}
2923
- *
2924
- */
2925
- dontSeeTraffic({ name, url }) {
2926
- if (!this.options.automationProtocol) {
2927
- console.log(
2928
- '* Switch to devtools protocol to use this command by setting devtoolsProtocol: true in the configuration',
2929
- )
2930
- return
2931
- }
2932
- dontSeeTraffic.call(this, ...arguments)
2933
- }
2934
2711
  }
2935
2712
 
2936
2713
  async function proceedSee(assertType, text, context, strict = false) {
@@ -2950,10 +2727,17 @@ async function proceedSee(assertType, text, context, strict = false) {
2950
2727
  const smartWaitEnabled = assertType === 'assert'
2951
2728
  const res = await this._locate(withStrictLocator(context), smartWaitEnabled)
2952
2729
  assertElementExists(res, context)
2953
- const selected = await forEachAsync(res, async (el) => this.browser.getElementText(getElementId(el)))
2730
+ let selected = await forEachAsync(res, async el => this.browser.getElementText(getElementId(el)))
2731
+
2732
+ // apply ignoreCase option
2733
+ if (store?.currentStep?.opts?.ignoreCase === true) {
2734
+ text = text.toLowerCase()
2735
+ selected = selected.map(elText => elText.toLowerCase())
2736
+ }
2737
+
2954
2738
  if (strict) {
2955
2739
  if (Array.isArray(selected) && selected.length !== 0) {
2956
- return selected.map((elText) => equals(description)[assertType](text, elText))
2740
+ return selected.map(elText => equals(description)[assertType](text, elText))
2957
2741
  }
2958
2742
  return equals(description)[assertType](text, selected)
2959
2743
  }
@@ -2981,7 +2765,7 @@ async function forEachAsync(array, callback, options = { expandArrayResults: tru
2981
2765
  const res = await callback(inputArray[index], index, inputArray)
2982
2766
 
2983
2767
  if (Array.isArray(res) && expandArrayResults) {
2984
- res.forEach((val) => values.push(val))
2768
+ res.forEach(val => values.push(val))
2985
2769
  } else if (res) {
2986
2770
  values.push(res)
2987
2771
  }
@@ -3067,11 +2851,11 @@ async function proceedSeeField(assertType, field, value) {
3067
2851
  const elem = usingFirstElement(res)
3068
2852
  const elemId = getElementId(elem)
3069
2853
 
3070
- const proceedMultiple = async (fields) => {
2854
+ const proceedMultiple = async fields => {
3071
2855
  const fieldResults = toArray(
3072
- await forEachAsync(fields, async (el) => {
2856
+ await forEachAsync(fields, async el => {
3073
2857
  const elementId = getElementId(el)
3074
- return this.browser.isW3C ? el.getValue() : this.browser.getElementAttribute(elementId, 'value')
2858
+ return this.browser.getElementAttribute(elementId, 'value')
3075
2859
  }),
3076
2860
  )
3077
2861
 
@@ -3080,27 +2864,24 @@ async function proceedSeeField(assertType, field, value) {
3080
2864
  } else {
3081
2865
  // Assert that results were found so the forEach assert does not silently pass
3082
2866
  equals(`no. of items matching > 0: ${field}`)[assertType](true, !!fieldResults.length)
3083
- fieldResults.forEach((val) => stringIncludes(`fields by ${field}`)[assertType](value, val))
2867
+ fieldResults.forEach(val => stringIncludes(`fields by ${field}`)[assertType](value, val))
3084
2868
  }
3085
2869
  }
3086
2870
 
3087
- const proceedSingle = (el) =>
3088
- el.getValue().then((res) => {
2871
+ const proceedSingle = el =>
2872
+ el.getValue().then(res => {
3089
2873
  if (res === null) {
3090
2874
  throw new Error(`Element ${el.selector} has no value attribute`)
3091
2875
  }
3092
2876
  stringIncludes(`fields by ${field}`)[assertType](value, res)
3093
2877
  })
3094
2878
 
3095
- const filterBySelected = async (elements) =>
3096
- filterAsync(elements, async (el) => this.browser.isElementSelected(getElementId(el)))
2879
+ const filterBySelected = async elements => filterAsync(elements, async el => this.browser.isElementSelected(getElementId(el)))
3097
2880
 
3098
2881
  const filterSelectedByValue = async (elements, value) => {
3099
- return filterAsync(elements, async (el) => {
2882
+ return filterAsync(elements, async el => {
3100
2883
  const elementId = getElementId(el)
3101
- const currentValue = this.browser.isW3C
3102
- ? await el.getValue()
3103
- : await this.browser.getElementAttribute(elementId, 'value')
2884
+ const currentValue = await this.browser.getElementAttribute(elementId, 'value')
3104
2885
  const isSelected = await this.browser.isElementSelected(elementId)
3105
2886
  return currentValue === value && isSelected
3106
2887
  })
@@ -3108,7 +2889,13 @@ async function proceedSeeField(assertType, field, value) {
3108
2889
 
3109
2890
  const tag = await elem.getTagName()
3110
2891
  if (tag === 'select') {
3111
- const subOptions = await this.browser.findElementsFromElement(elemId, 'css', 'option')
2892
+ let subOptions
2893
+
2894
+ try {
2895
+ subOptions = await this.browser.findElementsFromElement(elemId, 'css', 'option')
2896
+ } catch (e) {
2897
+ subOptions = await this.browser.findElementsFromElement(elemId, 'xpath', 'option')
2898
+ }
3112
2899
 
3113
2900
  if (value === '') {
3114
2901
  // Don't filter by value
@@ -3149,7 +2936,7 @@ async function proceedSeeCheckbox(assertType, field) {
3149
2936
  const res = await findFields.call(this, field)
3150
2937
  assertElementExists(res, field, 'Field')
3151
2938
 
3152
- const selected = await forEachAsync(res, async (el) => this.browser.isElementSelected(getElementId(el)))
2939
+ const selected = await forEachAsync(res, async el => this.browser.isElementSelected(getElementId(el)))
3153
2940
  return truth(`checkable field "${field}"`, 'to be checked')[assertType](selected)
3154
2941
  }
3155
2942
 
@@ -3213,7 +3000,6 @@ function getElementId(el) {
3213
3000
  // List of known key values to unicode code points
3214
3001
  // https://www.w3.org/TR/webdriver/#keyboard-actions
3215
3002
  const keyUnicodeMap = {
3216
- /* eslint-disable quote-props */
3217
3003
  Unidentified: '\uE000',
3218
3004
  Cancel: '\uE001',
3219
3005
  Clear: '\uE005',
@@ -3328,7 +3114,6 @@ const keyUnicodeMap = {
3328
3114
  Semicolon: '\uE018', // ';' alias
3329
3115
  Slash: '/', // '/' alias
3330
3116
  ZenkakuHankaku: '\uE040',
3331
- /* eslint-enable quote-props */
3332
3117
  }
3333
3118
 
3334
3119
  function convertKeyToRawKey(key) {
@@ -3352,7 +3137,7 @@ function getNormalizedKey(key) {
3352
3137
  return convertKeyToRawKey(normalizedKey)
3353
3138
  }
3354
3139
 
3355
- const unicodeModifierKeys = modifierKeys.map((k) => convertKeyToRawKey(k))
3140
+ const unicodeModifierKeys = modifierKeys.map(k => convertKeyToRawKey(k))
3356
3141
  function isModifierKey(key) {
3357
3142
  return unicodeModifierKeys.includes(key)
3358
3143
  }
@@ -3365,9 +3150,9 @@ function highlightActiveElement(element) {
3365
3150
 
3366
3151
  function prepareLocateFn(context) {
3367
3152
  if (!context) return this._locate.bind(this)
3368
- return (l) => {
3153
+ return l => {
3369
3154
  l = new Locator(l, 'css')
3370
- return this._locate(context, true).then(async (res) => {
3155
+ return this._locate(context, true).then(async res => {
3371
3156
  assertElementExists(res, context, 'Context element')
3372
3157
  if (l.react) {
3373
3158
  return res[0].react$$(l.react, l.props || undefined)
@@ -3377,4 +3162,8 @@ function prepareLocateFn(context) {
3377
3162
  }
3378
3163
  }
3379
3164
 
3165
+ function logEvents(event) {
3166
+ browserLogs.push(event.text) // add log message to the array
3167
+ }
3168
+
3380
3169
  module.exports = WebDriver