codeceptjs 3.6.4 → 3.6.5-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/bin/codecept.js +84 -63
- package/lib/assert/empty.js +19 -19
- package/lib/assert/equal.js +32 -30
- package/lib/assert/error.js +14 -14
- package/lib/assert/include.js +42 -42
- package/lib/assert/throws.js +13 -11
- package/lib/assert/truth.js +17 -18
- package/lib/command/configMigrate.js +57 -52
- package/lib/command/definitions.js +88 -88
- package/lib/command/dryRun.js +65 -63
- package/lib/command/generate.js +191 -181
- package/lib/command/info.js +39 -37
- package/lib/command/init.js +289 -286
- package/lib/command/interactive.js +32 -32
- package/lib/command/list.js +26 -26
- package/lib/command/run-multiple.js +113 -93
- package/lib/command/run-rerun.js +22 -22
- package/lib/command/run-workers.js +63 -63
- package/lib/command/run.js +24 -26
- package/lib/command/utils.js +64 -63
- package/lib/data/context.js +60 -60
- package/lib/data/dataScenarioConfig.js +47 -47
- package/lib/data/dataTableArgument.js +29 -29
- package/lib/data/table.js +26 -20
- package/lib/helper/AI.js +67 -65
- package/lib/helper/ApiDataFactory.js +72 -69
- package/lib/helper/Appium.js +409 -379
- package/lib/helper/ExpectHelper.js +214 -248
- package/lib/helper/FileSystem.js +77 -78
- package/lib/helper/GraphQL.js +44 -43
- package/lib/helper/GraphQLDataFactory.js +49 -50
- package/lib/helper/JSONResponse.js +64 -62
- package/lib/helper/Mochawesome.js +28 -28
- package/lib/helper/MockServer.js +12 -12
- package/lib/helper/Nightmare.js +664 -572
- package/lib/helper/Playwright.js +1320 -1211
- package/lib/helper/Protractor.js +663 -629
- package/lib/helper/Puppeteer.js +1232 -1124
- package/lib/helper/REST.js +87 -72
- package/lib/helper/TestCafe.js +490 -491
- package/lib/helper/WebDriver.js +1294 -1156
- package/lib/interfaces/bdd.js +38 -51
- package/lib/interfaces/featureConfig.js +19 -19
- package/lib/interfaces/gherkin.js +122 -111
- package/lib/interfaces/scenarioConfig.js +29 -29
- package/lib/listener/artifacts.js +9 -9
- package/lib/listener/config.js +24 -23
- package/lib/listener/exit.js +12 -12
- package/lib/listener/helpers.js +42 -42
- package/lib/listener/mocha.js +11 -11
- package/lib/listener/retry.js +32 -30
- package/lib/listener/steps.js +50 -51
- package/lib/listener/timeout.js +53 -53
- package/lib/plugin/allure.js +14 -14
- package/lib/plugin/autoDelay.js +29 -36
- package/lib/plugin/autoLogin.js +70 -66
- package/lib/plugin/commentStep.js +18 -18
- package/lib/plugin/coverage.js +92 -77
- package/lib/plugin/customLocator.js +20 -19
- package/lib/plugin/debugErrors.js +24 -24
- package/lib/plugin/eachElement.js +37 -37
- package/lib/plugin/fakerTransform.js +6 -6
- package/lib/plugin/heal.js +66 -63
- package/lib/plugin/pauseOnFail.js +10 -10
- package/lib/plugin/retryFailedStep.js +31 -38
- package/lib/plugin/retryTo.js +28 -28
- package/lib/plugin/screenshotOnFail.js +107 -86
- package/lib/plugin/selenoid.js +131 -117
- package/lib/plugin/standardActingHelpers.js +2 -8
- package/lib/plugin/stepByStepReport.js +102 -92
- package/lib/plugin/stepTimeout.js +23 -22
- package/lib/plugin/subtitles.js +34 -34
- package/lib/plugin/tryTo.js +39 -29
- package/lib/plugin/wdio.js +77 -72
- package/lib/template/heal.js +11 -14
- package/package.json +4 -2
- package/translations/de-DE.js +1 -1
- package/translations/fr-FR.js +1 -1
- package/translations/index.js +9 -9
- package/translations/it-IT.js +1 -1
- package/translations/ja-JP.js +1 -1
- package/translations/pl-PL.js +1 -1
- package/translations/pt-BR.js +1 -1
- package/translations/ru-RU.js +1 -1
- package/translations/zh-CN.js +1 -1
- package/translations/zh-TW.js +1 -1
- package/typings/promiseBasedTypes.d.ts +238 -0
- package/typings/types.d.ts +32 -0
package/lib/helper/WebDriver.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
let webdriverio
|
|
2
|
-
|
|
3
|
-
const assert = require('assert')
|
|
4
|
-
const path = require('path')
|
|
5
|
-
|
|
6
|
-
const Helper = require('@codeceptjs/helper')
|
|
7
|
-
const promiseRetry = require('promise-retry')
|
|
8
|
-
const stringIncludes = require('../assert/include').includes
|
|
9
|
-
const { urlEquals, equals } = require('../assert/equal')
|
|
10
|
-
const { debug } = require('../output')
|
|
11
|
-
const { empty } = require('../assert/empty')
|
|
12
|
-
const { truth } = require('../assert/truth')
|
|
1
|
+
let webdriverio
|
|
2
|
+
|
|
3
|
+
const assert = require('assert')
|
|
4
|
+
const path = require('path')
|
|
5
|
+
|
|
6
|
+
const Helper = require('@codeceptjs/helper')
|
|
7
|
+
const promiseRetry = require('promise-retry')
|
|
8
|
+
const stringIncludes = require('../assert/include').includes
|
|
9
|
+
const { urlEquals, equals } = require('../assert/equal')
|
|
10
|
+
const { debug } = require('../output')
|
|
11
|
+
const { empty } = require('../assert/empty')
|
|
12
|
+
const { truth } = require('../assert/truth')
|
|
13
13
|
const {
|
|
14
14
|
xpathLocator,
|
|
15
15
|
fileExists,
|
|
@@ -19,26 +19,30 @@ const {
|
|
|
19
19
|
screenshotOutputFolder,
|
|
20
20
|
getNormalizedKeyAttributeValue,
|
|
21
21
|
modifierKeys,
|
|
22
|
-
} = require('../utils')
|
|
22
|
+
} = require('../utils')
|
|
23
|
+
const { isColorProperty, convertColorToRGBA } = require('../colorUtils')
|
|
24
|
+
const ElementNotFound = require('./errors/ElementNotFound')
|
|
25
|
+
const ConnectionRefused = require('./errors/ConnectionRefused')
|
|
26
|
+
const Locator = require('../locator')
|
|
27
|
+
const { highlightElement } = require('./scripts/highlightElement')
|
|
28
|
+
const { focusElement } = require('./scripts/focusElement')
|
|
29
|
+
const { blurElement } = require('./scripts/blurElement')
|
|
23
30
|
const {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
const Locator = require('../locator');
|
|
30
|
-
const { highlightElement } = require('./scripts/highlightElement');
|
|
31
|
-
const { focusElement } = require('./scripts/focusElement');
|
|
32
|
-
const { blurElement } = require('./scripts/blurElement');
|
|
31
|
+
dontSeeElementError,
|
|
32
|
+
seeElementError,
|
|
33
|
+
seeElementInDOMError,
|
|
34
|
+
dontSeeElementInDOMError,
|
|
35
|
+
} = require('./errors/ElementAssertion')
|
|
33
36
|
const {
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
37
|
+
dontSeeTraffic,
|
|
38
|
+
seeTraffic,
|
|
39
|
+
grabRecordedNetworkTraffics,
|
|
40
|
+
stopRecordingTraffic,
|
|
41
|
+
flushNetworkTraffics,
|
|
42
|
+
} = require('./network/actions')
|
|
39
43
|
|
|
40
|
-
const SHADOW = 'shadow'
|
|
41
|
-
const webRoot = 'body'
|
|
44
|
+
const SHADOW = 'shadow'
|
|
45
|
+
const webRoot = 'body'
|
|
42
46
|
|
|
43
47
|
/**
|
|
44
48
|
* ## Configuration
|
|
@@ -70,7 +74,7 @@ const webRoot = 'body';
|
|
|
70
74
|
* @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
|
|
71
75
|
* @prop {boolean} [devtoolsProtocol=false] - enable devtools protocol. Default: false. More info: https://webdriver.io/docs/automationProtocols/#devtools-protocol.
|
|
72
76
|
*/
|
|
73
|
-
const config = {}
|
|
77
|
+
const config = {}
|
|
74
78
|
|
|
75
79
|
/**
|
|
76
80
|
* WebDriver helper which wraps [webdriverio](http://webdriver.io/) library to
|
|
@@ -441,34 +445,34 @@ const config = {};
|
|
|
441
445
|
*/
|
|
442
446
|
class WebDriver extends Helper {
|
|
443
447
|
constructor(config) {
|
|
444
|
-
super(config)
|
|
445
|
-
webdriverio = require('webdriverio')
|
|
448
|
+
super(config)
|
|
449
|
+
webdriverio = require('webdriverio')
|
|
446
450
|
|
|
447
451
|
// set defaults
|
|
448
|
-
this.root = webRoot
|
|
449
|
-
this.isWeb = true
|
|
450
|
-
this.isRunning = false
|
|
451
|
-
this.sessionWindows = {}
|
|
452
|
-
this.activeSessionName = ''
|
|
453
|
-
this.customLocatorStrategies = config.customLocatorStrategies
|
|
452
|
+
this.root = webRoot
|
|
453
|
+
this.isWeb = true
|
|
454
|
+
this.isRunning = false
|
|
455
|
+
this.sessionWindows = {}
|
|
456
|
+
this.activeSessionName = ''
|
|
457
|
+
this.customLocatorStrategies = config.customLocatorStrategies
|
|
454
458
|
|
|
455
459
|
// for network stuff
|
|
456
|
-
this.requests = []
|
|
457
|
-
this.recording = false
|
|
458
|
-
this.recordedAtLeastOnce = false
|
|
460
|
+
this.requests = []
|
|
461
|
+
this.recording = false
|
|
462
|
+
this.recordedAtLeastOnce = false
|
|
459
463
|
|
|
460
|
-
this._setConfig(config)
|
|
464
|
+
this._setConfig(config)
|
|
461
465
|
|
|
462
466
|
Locator.addFilter((locator, result) => {
|
|
463
467
|
if (typeof locator === 'string' && locator.indexOf('~') === 0) {
|
|
464
468
|
// accessibility locator
|
|
465
469
|
if (this.isWeb) {
|
|
466
|
-
result.value = `[aria-label="${locator.slice(1)}"]
|
|
467
|
-
result.type = 'css'
|
|
468
|
-
result.output = `aria-label=${locator.slice(1)}
|
|
470
|
+
result.value = `[aria-label="${locator.slice(1)}"]`
|
|
471
|
+
result.type = 'css'
|
|
472
|
+
result.output = `aria-label=${locator.slice(1)}`
|
|
469
473
|
}
|
|
470
474
|
}
|
|
471
|
-
})
|
|
475
|
+
})
|
|
472
476
|
}
|
|
473
477
|
|
|
474
478
|
_validateConfig(config) {
|
|
@@ -488,41 +492,41 @@ class WebDriver extends Helper {
|
|
|
488
492
|
keepBrowserState: false,
|
|
489
493
|
deprecationWarnings: false,
|
|
490
494
|
highlightElement: false,
|
|
491
|
-
}
|
|
495
|
+
}
|
|
492
496
|
|
|
493
497
|
// override defaults with config
|
|
494
|
-
config = Object.assign(defaults, config)
|
|
498
|
+
config = Object.assign(defaults, config)
|
|
495
499
|
|
|
496
500
|
if (config.host) {
|
|
497
501
|
// webdriverio spec
|
|
498
|
-
config.hostname = config.host
|
|
499
|
-
config.path = config.path ? config.path : '/wd/hub'
|
|
502
|
+
config.hostname = config.host
|
|
503
|
+
config.path = config.path ? config.path : '/wd/hub'
|
|
500
504
|
}
|
|
501
505
|
|
|
502
|
-
config.baseUrl = config.url || config.baseUrl
|
|
506
|
+
config.baseUrl = config.url || config.baseUrl
|
|
503
507
|
if (config.desiredCapabilities && Object.keys(config.desiredCapabilities).length) {
|
|
504
|
-
config.capabilities = config.desiredCapabilities
|
|
508
|
+
config.capabilities = config.desiredCapabilities
|
|
505
509
|
}
|
|
506
|
-
config.capabilities.browserName = config.browser || config.capabilities.browserName
|
|
507
|
-
config.capabilities.browserVersion = config.browserVersion || config.capabilities.browserVersion
|
|
510
|
+
config.capabilities.browserName = config.browser || config.capabilities.browserName
|
|
511
|
+
config.capabilities.browserVersion = config.browserVersion || config.capabilities.browserVersion
|
|
508
512
|
if (config.capabilities.chromeOptions) {
|
|
509
|
-
config.capabilities['goog:chromeOptions'] = config.capabilities.chromeOptions
|
|
510
|
-
delete config.capabilities.chromeOptions
|
|
513
|
+
config.capabilities['goog:chromeOptions'] = config.capabilities.chromeOptions
|
|
514
|
+
delete config.capabilities.chromeOptions
|
|
511
515
|
}
|
|
512
516
|
if (config.capabilities.firefoxOptions) {
|
|
513
|
-
config.capabilities['moz:firefoxOptions'] = config.capabilities.firefoxOptions
|
|
514
|
-
delete config.capabilities.firefoxOptions
|
|
517
|
+
config.capabilities['moz:firefoxOptions'] = config.capabilities.firefoxOptions
|
|
518
|
+
delete config.capabilities.firefoxOptions
|
|
515
519
|
}
|
|
516
520
|
if (config.capabilities.ieOptions) {
|
|
517
|
-
config.capabilities['se:ieOptions'] = config.capabilities.ieOptions
|
|
518
|
-
delete config.capabilities.ieOptions
|
|
521
|
+
config.capabilities['se:ieOptions'] = config.capabilities.ieOptions
|
|
522
|
+
delete config.capabilities.ieOptions
|
|
519
523
|
}
|
|
520
524
|
if (config.capabilities.selenoidOptions) {
|
|
521
|
-
config.capabilities['selenoid:options'] = config.capabilities.selenoidOptions
|
|
522
|
-
delete config.capabilities.selenoidOptions
|
|
525
|
+
config.capabilities['selenoid:options'] = config.capabilities.selenoidOptions
|
|
526
|
+
delete config.capabilities.selenoidOptions
|
|
523
527
|
}
|
|
524
528
|
|
|
525
|
-
config.waitForTimeoutInSeconds = config.waitForTimeout / 1000
|
|
529
|
+
config.waitForTimeoutInSeconds = config.waitForTimeout / 1000 // convert to seconds
|
|
526
530
|
|
|
527
531
|
if (!config.capabilities.platformName && (!config.url || !config.browser)) {
|
|
528
532
|
throw new Error(`
|
|
@@ -536,197 +540,201 @@ class WebDriver extends Helper {
|
|
|
536
540
|
}
|
|
537
541
|
}
|
|
538
542
|
}
|
|
539
|
-
`)
|
|
543
|
+
`)
|
|
540
544
|
}
|
|
541
545
|
|
|
542
|
-
return config
|
|
546
|
+
return config
|
|
543
547
|
}
|
|
544
548
|
|
|
545
549
|
static _checkRequirements() {
|
|
546
550
|
try {
|
|
547
|
-
require('webdriverio')
|
|
551
|
+
require('webdriverio')
|
|
548
552
|
} catch (e) {
|
|
549
|
-
return ['webdriverio@^6.12.1']
|
|
553
|
+
return ['webdriverio@^6.12.1']
|
|
550
554
|
}
|
|
551
555
|
}
|
|
552
556
|
|
|
553
557
|
static _config() {
|
|
554
|
-
return [
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
558
|
+
return [
|
|
559
|
+
{
|
|
560
|
+
name: 'url',
|
|
561
|
+
message: 'Base url of site to be tested',
|
|
562
|
+
default: 'http://localhost',
|
|
563
|
+
},
|
|
564
|
+
{
|
|
565
|
+
name: 'browser',
|
|
566
|
+
message: 'Browser in which testing will be performed',
|
|
567
|
+
default: 'chrome',
|
|
568
|
+
},
|
|
569
|
+
]
|
|
563
570
|
}
|
|
564
571
|
|
|
565
572
|
_beforeSuite() {
|
|
566
573
|
if (!this.options.restart && !this.options.manualStart && !this.isRunning) {
|
|
567
|
-
this.debugSection('Session', 'Starting singleton browser session')
|
|
568
|
-
return this._startBrowser()
|
|
574
|
+
this.debugSection('Session', 'Starting singleton browser session')
|
|
575
|
+
return this._startBrowser()
|
|
569
576
|
}
|
|
570
577
|
}
|
|
571
578
|
|
|
572
579
|
_lookupCustomLocator(customStrategy) {
|
|
573
|
-
if (typeof
|
|
574
|
-
return null
|
|
580
|
+
if (typeof this.customLocatorStrategies !== 'object') {
|
|
581
|
+
return null
|
|
575
582
|
}
|
|
576
|
-
const strategy = this.customLocatorStrategies[customStrategy]
|
|
577
|
-
return typeof
|
|
583
|
+
const strategy = this.customLocatorStrategies[customStrategy]
|
|
584
|
+
return typeof strategy === 'function' ? strategy : null
|
|
578
585
|
}
|
|
579
586
|
|
|
580
587
|
_isCustomLocator(locator) {
|
|
581
|
-
const locatorObj = new Locator(locator)
|
|
588
|
+
const locatorObj = new Locator(locator)
|
|
582
589
|
if (locatorObj.isCustom()) {
|
|
583
|
-
const customLocator = this._lookupCustomLocator(locatorObj.type)
|
|
590
|
+
const customLocator = this._lookupCustomLocator(locatorObj.type)
|
|
584
591
|
if (customLocator) {
|
|
585
|
-
return true
|
|
592
|
+
return true
|
|
586
593
|
}
|
|
587
|
-
throw new Error('Please define "customLocatorStrategies" as an Object and the Locator Strategy as a "function".')
|
|
594
|
+
throw new Error('Please define "customLocatorStrategies" as an Object and the Locator Strategy as a "function".')
|
|
588
595
|
}
|
|
589
|
-
return false
|
|
596
|
+
return false
|
|
590
597
|
}
|
|
591
598
|
|
|
592
599
|
async _res(locator) {
|
|
593
|
-
const res =
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
600
|
+
const res =
|
|
601
|
+
this._isShadowLocator(locator) || this._isCustomLocator(locator)
|
|
602
|
+
? await this._locate(locator)
|
|
603
|
+
: await this.$$(withStrictLocator(locator))
|
|
604
|
+
return res
|
|
597
605
|
}
|
|
598
606
|
|
|
599
607
|
async _startBrowser() {
|
|
600
608
|
try {
|
|
601
609
|
if (this.options.multiremote) {
|
|
602
|
-
this.browser = await webdriverio.multiremote(this.options.multiremote)
|
|
610
|
+
this.browser = await webdriverio.multiremote(this.options.multiremote)
|
|
603
611
|
} else {
|
|
604
612
|
// remove non w3c capabilities
|
|
605
|
-
delete this.options.capabilities.protocol
|
|
606
|
-
delete this.options.capabilities.hostname
|
|
607
|
-
delete this.options.capabilities.port
|
|
608
|
-
delete this.options.capabilities.path
|
|
613
|
+
delete this.options.capabilities.protocol
|
|
614
|
+
delete this.options.capabilities.hostname
|
|
615
|
+
delete this.options.capabilities.port
|
|
616
|
+
delete this.options.capabilities.path
|
|
609
617
|
if (this.options.devtoolsProtocol) {
|
|
610
|
-
if (!['chrome', 'chromium'].includes(this.options.browser.toLowerCase()))
|
|
611
|
-
|
|
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'
|
|
612
621
|
}
|
|
613
|
-
this.browser = await webdriverio.remote(this.options)
|
|
622
|
+
this.browser = await webdriverio.remote(this.options)
|
|
614
623
|
}
|
|
615
624
|
} catch (err) {
|
|
616
625
|
if (err.toString().indexOf('ECONNREFUSED')) {
|
|
617
|
-
throw new ConnectionRefused(err)
|
|
626
|
+
throw new ConnectionRefused(err)
|
|
618
627
|
}
|
|
619
|
-
throw err
|
|
628
|
+
throw err
|
|
620
629
|
}
|
|
621
630
|
|
|
622
|
-
this.isRunning = true
|
|
631
|
+
this.isRunning = true
|
|
623
632
|
if (this.options.timeouts && this.isWeb) {
|
|
624
|
-
await this.defineTimeout(this.options.timeouts)
|
|
633
|
+
await this.defineTimeout(this.options.timeouts)
|
|
625
634
|
}
|
|
626
635
|
|
|
627
|
-
await this._resizeWindowIfNeeded(this.browser, this.options.windowSize)
|
|
636
|
+
await this._resizeWindowIfNeeded(this.browser, this.options.windowSize)
|
|
628
637
|
|
|
629
|
-
this.$$ = this.browser.$$.bind(this.browser)
|
|
638
|
+
this.$$ = this.browser.$$.bind(this.browser)
|
|
630
639
|
|
|
631
640
|
if (this._isCustomLocatorStrategyDefined()) {
|
|
632
641
|
Object.keys(this.customLocatorStrategies).forEach(async (customLocator) => {
|
|
633
|
-
this.debugSection('Weddriver', `adding custom locator strategy: ${customLocator}`)
|
|
634
|
-
const locatorFunction = this._lookupCustomLocator(customLocator)
|
|
635
|
-
this.browser.addLocatorStrategy(customLocator, locatorFunction)
|
|
636
|
-
})
|
|
642
|
+
this.debugSection('Weddriver', `adding custom locator strategy: ${customLocator}`)
|
|
643
|
+
const locatorFunction = this._lookupCustomLocator(customLocator)
|
|
644
|
+
this.browser.addLocatorStrategy(customLocator, locatorFunction)
|
|
645
|
+
})
|
|
637
646
|
}
|
|
638
647
|
|
|
639
648
|
if (this.browser.capabilities && this.browser.capabilities.platformName) {
|
|
640
|
-
this.browser.capabilities.platformName = this.browser.capabilities.platformName.toLowerCase()
|
|
649
|
+
this.browser.capabilities.platformName = this.browser.capabilities.platformName.toLowerCase()
|
|
641
650
|
}
|
|
642
651
|
|
|
643
652
|
if (this.options.automationProtocol) {
|
|
644
|
-
this.puppeteerBrowser = await this.browser.getPuppeteer()
|
|
645
|
-
this.page = (await this.puppeteerBrowser.pages())[0]
|
|
653
|
+
this.puppeteerBrowser = await this.browser.getPuppeteer()
|
|
654
|
+
this.page = (await this.puppeteerBrowser.pages())[0]
|
|
646
655
|
}
|
|
647
656
|
|
|
648
|
-
return this.browser
|
|
657
|
+
return this.browser
|
|
649
658
|
}
|
|
650
659
|
|
|
651
660
|
_isCustomLocatorStrategyDefined() {
|
|
652
|
-
return this.customLocatorStrategies && Object.keys(this.customLocatorStrategies).length
|
|
661
|
+
return this.customLocatorStrategies && Object.keys(this.customLocatorStrategies).length
|
|
653
662
|
}
|
|
654
663
|
|
|
655
664
|
async _stopBrowser() {
|
|
656
|
-
if (this.browser && this.isRunning) await this.browser.deleteSession()
|
|
665
|
+
if (this.browser && this.isRunning) await this.browser.deleteSession()
|
|
657
666
|
}
|
|
658
667
|
|
|
659
668
|
async _before() {
|
|
660
|
-
this.context = this.root
|
|
661
|
-
if (this.options.restart && !this.options.manualStart) return this._startBrowser()
|
|
662
|
-
if (!this.isRunning && !this.options.manualStart) return this._startBrowser()
|
|
663
|
-
if (this.browser) this.$$ = this.browser.$$.bind(this.browser)
|
|
664
|
-
return this.browser
|
|
669
|
+
this.context = this.root
|
|
670
|
+
if (this.options.restart && !this.options.manualStart) return this._startBrowser()
|
|
671
|
+
if (!this.isRunning && !this.options.manualStart) return this._startBrowser()
|
|
672
|
+
if (this.browser) this.$$ = this.browser.$$.bind(this.browser)
|
|
673
|
+
return this.browser
|
|
665
674
|
}
|
|
666
675
|
|
|
667
676
|
async _after() {
|
|
668
|
-
if (!this.isRunning) return
|
|
677
|
+
if (!this.isRunning) return
|
|
669
678
|
if (this.options.restart) {
|
|
670
|
-
this.isRunning = false
|
|
671
|
-
return this.browser.deleteSession()
|
|
679
|
+
this.isRunning = false
|
|
680
|
+
return this.browser.deleteSession()
|
|
672
681
|
}
|
|
673
|
-
if (this.browser.isInsideFrame) await this.browser.switchToFrame(null)
|
|
682
|
+
if (this.browser.isInsideFrame) await this.browser.switchToFrame(null)
|
|
674
683
|
|
|
675
|
-
if (this.options.keepBrowserState) return
|
|
684
|
+
if (this.options.keepBrowserState) return
|
|
676
685
|
|
|
677
686
|
if (!this.options.keepCookies && this.options.capabilities.browserName) {
|
|
678
|
-
this.debugSection('Session', 'cleaning cookies and localStorage')
|
|
679
|
-
await this.browser.deleteCookies()
|
|
687
|
+
this.debugSection('Session', 'cleaning cookies and localStorage')
|
|
688
|
+
await this.browser.deleteCookies()
|
|
680
689
|
}
|
|
681
690
|
await this.browser.execute('localStorage.clear();').catch((err) => {
|
|
682
|
-
if (!(err.message.indexOf("Storage is disabled inside 'data:' URLs.") > -1)) throw err
|
|
683
|
-
})
|
|
684
|
-
await this.closeOtherTabs()
|
|
685
|
-
return this.browser
|
|
691
|
+
if (!(err.message.indexOf("Storage is disabled inside 'data:' URLs.") > -1)) throw err
|
|
692
|
+
})
|
|
693
|
+
await this.closeOtherTabs()
|
|
694
|
+
return this.browser
|
|
686
695
|
}
|
|
687
696
|
|
|
688
|
-
_afterSuite() {
|
|
689
|
-
}
|
|
697
|
+
_afterSuite() {}
|
|
690
698
|
|
|
691
699
|
_finishTest() {
|
|
692
|
-
if (!this.options.restart && this.isRunning) return this._stopBrowser()
|
|
700
|
+
if (!this.options.restart && this.isRunning) return this._stopBrowser()
|
|
693
701
|
}
|
|
694
702
|
|
|
695
703
|
_session() {
|
|
696
|
-
const defaultSession = this.browser
|
|
704
|
+
const defaultSession = this.browser
|
|
697
705
|
return {
|
|
698
706
|
start: async (sessionName, opts) => {
|
|
699
707
|
// opts.disableScreenshots = true; // screenshots cant be saved as session will be already closed
|
|
700
|
-
opts = this._validateConfig(Object.assign(this.options, opts))
|
|
701
|
-
this.debugSection('New Browser', JSON.stringify(opts))
|
|
702
|
-
const browser = await webdriverio.remote(opts)
|
|
703
|
-
this.activeSessionName = sessionName
|
|
708
|
+
opts = this._validateConfig(Object.assign(this.options, opts))
|
|
709
|
+
this.debugSection('New Browser', JSON.stringify(opts))
|
|
710
|
+
const browser = await webdriverio.remote(opts)
|
|
711
|
+
this.activeSessionName = sessionName
|
|
704
712
|
if (opts.timeouts && this.isWeb) {
|
|
705
|
-
await this._defineBrowserTimeout(browser, opts.timeouts)
|
|
713
|
+
await this._defineBrowserTimeout(browser, opts.timeouts)
|
|
706
714
|
}
|
|
707
715
|
|
|
708
|
-
await this._resizeWindowIfNeeded(browser, opts.windowSize)
|
|
716
|
+
await this._resizeWindowIfNeeded(browser, opts.windowSize)
|
|
709
717
|
|
|
710
|
-
return browser
|
|
718
|
+
return browser
|
|
711
719
|
},
|
|
712
720
|
stop: async (browser) => {
|
|
713
|
-
if (!browser) return
|
|
714
|
-
return browser.deleteSession()
|
|
721
|
+
if (!browser) return
|
|
722
|
+
return browser.deleteSession()
|
|
715
723
|
},
|
|
716
724
|
loadVars: async (browser) => {
|
|
717
|
-
if (this.context !== this.root) throw new Error(
|
|
718
|
-
this.browser = browser
|
|
719
|
-
this.$$ = this.browser.$$.bind(this.browser)
|
|
720
|
-
this.sessionWindows[this.activeSessionName] = browser
|
|
725
|
+
if (this.context !== this.root) throw new Error("Can't start session inside within block")
|
|
726
|
+
this.browser = browser
|
|
727
|
+
this.$$ = this.browser.$$.bind(this.browser)
|
|
728
|
+
this.sessionWindows[this.activeSessionName] = browser
|
|
721
729
|
},
|
|
722
730
|
restoreVars: async (session) => {
|
|
723
731
|
if (!session) {
|
|
724
|
-
this.activeSessionName = ''
|
|
732
|
+
this.activeSessionName = ''
|
|
725
733
|
}
|
|
726
|
-
this.browser = defaultSession
|
|
727
|
-
this.$$ = this.browser.$$.bind(this.browser)
|
|
734
|
+
this.browser = defaultSession
|
|
735
|
+
this.$$ = this.browser.$$.bind(this.browser)
|
|
728
736
|
},
|
|
729
|
-
}
|
|
737
|
+
}
|
|
730
738
|
}
|
|
731
739
|
|
|
732
740
|
/**
|
|
@@ -748,41 +756,41 @@ class WebDriver extends Helper {
|
|
|
748
756
|
* @param {function} fn async functuion that executed with WebDriver helper as argument
|
|
749
757
|
*/
|
|
750
758
|
useWebDriverTo(description, fn) {
|
|
751
|
-
return this._useTo(...arguments)
|
|
759
|
+
return this._useTo(...arguments)
|
|
752
760
|
}
|
|
753
761
|
|
|
754
762
|
async _failed() {
|
|
755
|
-
if (this.context !== this.root) await this._withinEnd()
|
|
763
|
+
if (this.context !== this.root) await this._withinEnd()
|
|
756
764
|
}
|
|
757
765
|
|
|
758
766
|
async _withinBegin(locator) {
|
|
759
|
-
const frame = isFrameLocator(locator)
|
|
767
|
+
const frame = isFrameLocator(locator)
|
|
760
768
|
if (frame) {
|
|
761
|
-
this.browser.isInsideFrame = true
|
|
769
|
+
this.browser.isInsideFrame = true
|
|
762
770
|
if (Array.isArray(frame)) {
|
|
763
771
|
// this.switchTo(null);
|
|
764
|
-
await forEachAsync(frame, async f => this.switchTo(f))
|
|
765
|
-
return
|
|
772
|
+
await forEachAsync(frame, async (f) => this.switchTo(f))
|
|
773
|
+
return
|
|
766
774
|
}
|
|
767
|
-
await this.switchTo(frame)
|
|
768
|
-
return
|
|
775
|
+
await this.switchTo(frame)
|
|
776
|
+
return
|
|
769
777
|
}
|
|
770
|
-
this.context = locator
|
|
778
|
+
this.context = locator
|
|
771
779
|
|
|
772
|
-
let res = await this.browser.$$(withStrictLocator(locator))
|
|
773
|
-
assertElementExists(res, locator)
|
|
774
|
-
res = usingFirstElement(res)
|
|
775
|
-
this.context = res.selector
|
|
776
|
-
this.$$ = res.$$.bind(res)
|
|
780
|
+
let res = await this.browser.$$(withStrictLocator(locator))
|
|
781
|
+
assertElementExists(res, locator)
|
|
782
|
+
res = usingFirstElement(res)
|
|
783
|
+
this.context = res.selector
|
|
784
|
+
this.$$ = res.$$.bind(res)
|
|
777
785
|
}
|
|
778
786
|
|
|
779
787
|
async _withinEnd() {
|
|
780
788
|
if (this.browser.isInsideFrame) {
|
|
781
|
-
this.browser.isInsideFrame = false
|
|
782
|
-
return this.switchTo(null)
|
|
789
|
+
this.browser.isInsideFrame = false
|
|
790
|
+
return this.switchTo(null)
|
|
783
791
|
}
|
|
784
|
-
this.context = this.root
|
|
785
|
-
this.$$ = this.browser.$$.bind(this.browser)
|
|
792
|
+
this.context = this.root
|
|
793
|
+
this.$$ = this.browser.$$.bind(this.browser)
|
|
786
794
|
}
|
|
787
795
|
|
|
788
796
|
/**
|
|
@@ -791,7 +799,7 @@ class WebDriver extends Helper {
|
|
|
791
799
|
* @param {object} locator
|
|
792
800
|
*/
|
|
793
801
|
_isShadowLocator(locator) {
|
|
794
|
-
return locator.type === SHADOW || locator[SHADOW]
|
|
802
|
+
return locator.type === SHADOW || locator[SHADOW]
|
|
795
803
|
}
|
|
796
804
|
|
|
797
805
|
/**
|
|
@@ -800,35 +808,37 @@ class WebDriver extends Helper {
|
|
|
800
808
|
* @param {object} locator
|
|
801
809
|
*/
|
|
802
810
|
async _locateShadow(locator) {
|
|
803
|
-
const shadow = locator.value ? locator.value : locator[SHADOW]
|
|
804
|
-
const shadowSequence = []
|
|
805
|
-
let elements
|
|
811
|
+
const shadow = locator.value ? locator.value : locator[SHADOW]
|
|
812
|
+
const shadowSequence = []
|
|
813
|
+
let elements
|
|
806
814
|
|
|
807
815
|
if (!Array.isArray(shadow)) {
|
|
808
|
-
throw new Error(`Shadow '${shadow}' should be defined as an Array of elements.`)
|
|
816
|
+
throw new Error(`Shadow '${shadow}' should be defined as an Array of elements.`)
|
|
809
817
|
}
|
|
810
818
|
|
|
811
819
|
// traverse through the Shadow locators in sequence
|
|
812
820
|
for (let index = 0; index < shadow.length; index++) {
|
|
813
|
-
const shadowElement = shadow[index]
|
|
814
|
-
shadowSequence.push(shadowElement)
|
|
821
|
+
const shadowElement = shadow[index]
|
|
822
|
+
shadowSequence.push(shadowElement)
|
|
815
823
|
|
|
816
824
|
if (!elements) {
|
|
817
|
-
elements = await
|
|
825
|
+
elements = await this.browser.$$(shadowElement)
|
|
818
826
|
} else if (Array.isArray(elements)) {
|
|
819
|
-
elements = await elements[0].shadow$$(shadowElement)
|
|
827
|
+
elements = await elements[0].shadow$$(shadowElement)
|
|
820
828
|
} else if (elements) {
|
|
821
|
-
elements = await elements.shadow$$(shadowElement)
|
|
829
|
+
elements = await elements.shadow$$(shadowElement)
|
|
822
830
|
}
|
|
823
831
|
|
|
824
832
|
if (!elements || !elements[0]) {
|
|
825
|
-
throw new Error(
|
|
833
|
+
throw new Error(
|
|
834
|
+
`Shadow Element '${shadowElement}' is not found. It is possible the element is incorrect or elements sequence is incorrect. Please verify the sequence '${shadowSequence.join('>')}' is correctly chained.`,
|
|
835
|
+
)
|
|
826
836
|
}
|
|
827
837
|
}
|
|
828
838
|
|
|
829
|
-
this.debugSection('Elements', `Found ${elements.length} '${SHADOW}' elements`)
|
|
839
|
+
this.debugSection('Elements', `Found ${elements.length} '${SHADOW}' elements`)
|
|
830
840
|
|
|
831
|
-
return elements
|
|
841
|
+
return elements
|
|
832
842
|
}
|
|
833
843
|
|
|
834
844
|
/**
|
|
@@ -837,8 +847,11 @@ class WebDriver extends Helper {
|
|
|
837
847
|
* @param {object} locator
|
|
838
848
|
*/
|
|
839
849
|
async _smartWait(locator) {
|
|
840
|
-
this.debugSection(
|
|
841
|
-
|
|
850
|
+
this.debugSection(
|
|
851
|
+
`SmartWait (${this.options.smartWait}ms)`,
|
|
852
|
+
`Locating ${JSON.stringify(locator)} in ${this.options.smartWait}`,
|
|
853
|
+
)
|
|
854
|
+
await this.defineTimeout({ implicit: this.options.smartWait })
|
|
842
855
|
}
|
|
843
856
|
|
|
844
857
|
/**
|
|
@@ -853,53 +866,53 @@ class WebDriver extends Helper {
|
|
|
853
866
|
* @param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
|
|
854
867
|
*/
|
|
855
868
|
async _locate(locator, smartWait = false) {
|
|
856
|
-
if (require('../store').debugMode) smartWait = false
|
|
869
|
+
if (require('../store').debugMode) smartWait = false
|
|
857
870
|
|
|
858
871
|
// special locator type for Shadow DOM
|
|
859
872
|
if (this._isShadowLocator(locator)) {
|
|
860
873
|
if (!this.options.smartWait || !smartWait) {
|
|
861
|
-
const els = await this._locateShadow(locator)
|
|
862
|
-
return els
|
|
874
|
+
const els = await this._locateShadow(locator)
|
|
875
|
+
return els
|
|
863
876
|
}
|
|
864
877
|
|
|
865
|
-
const els = await this._locateShadow(locator)
|
|
866
|
-
return els
|
|
878
|
+
const els = await this._locateShadow(locator)
|
|
879
|
+
return els
|
|
867
880
|
}
|
|
868
881
|
|
|
869
882
|
// special locator type for React
|
|
870
883
|
if (locator.react) {
|
|
871
|
-
const els = await this.browser.react$$(locator.react, locator.props || undefined, locator.state || undefined)
|
|
872
|
-
this.debugSection('Elements', `Found ${els.length} react components`)
|
|
873
|
-
return els
|
|
884
|
+
const els = await this.browser.react$$(locator.react, locator.props || undefined, locator.state || undefined)
|
|
885
|
+
this.debugSection('Elements', `Found ${els.length} react components`)
|
|
886
|
+
return els
|
|
874
887
|
}
|
|
875
888
|
|
|
876
889
|
if (!this.options.smartWait || !smartWait) {
|
|
877
890
|
if (this._isCustomLocator(locator)) {
|
|
878
|
-
const locatorObj = new Locator(locator)
|
|
879
|
-
return this.browser.custom$$(locatorObj.type, locatorObj.value)
|
|
891
|
+
const locatorObj = new Locator(locator)
|
|
892
|
+
return this.browser.custom$$(locatorObj.type, locatorObj.value)
|
|
880
893
|
}
|
|
881
894
|
|
|
882
|
-
const els = await this.$$(withStrictLocator(locator))
|
|
883
|
-
return els
|
|
895
|
+
const els = await this.$$(withStrictLocator(locator))
|
|
896
|
+
return els
|
|
884
897
|
}
|
|
885
898
|
|
|
886
|
-
await this._smartWait(locator)
|
|
899
|
+
await this._smartWait(locator)
|
|
887
900
|
|
|
888
901
|
if (this._isCustomLocator(locator)) {
|
|
889
|
-
const locatorObj = new Locator(locator)
|
|
890
|
-
return this.browser.custom$$(locatorObj.type, locatorObj.value)
|
|
902
|
+
const locatorObj = new Locator(locator)
|
|
903
|
+
return this.browser.custom$$(locatorObj.type, locatorObj.value)
|
|
891
904
|
}
|
|
892
905
|
|
|
893
|
-
const els = await this.$$(withStrictLocator(locator))
|
|
894
|
-
await this.defineTimeout({ implicit: 0 })
|
|
895
|
-
return els
|
|
906
|
+
const els = await this.$$(withStrictLocator(locator))
|
|
907
|
+
await this.defineTimeout({ implicit: 0 })
|
|
908
|
+
return els
|
|
896
909
|
}
|
|
897
910
|
|
|
898
911
|
_grabCustomLocator(locator) {
|
|
899
912
|
if (typeof locator === 'string') {
|
|
900
|
-
locator = new Locator(locator)
|
|
913
|
+
locator = new Locator(locator)
|
|
901
914
|
}
|
|
902
|
-
return locator.value ? locator.value : locator.custom
|
|
915
|
+
return locator.value ? locator.value : locator.custom
|
|
903
916
|
}
|
|
904
917
|
|
|
905
918
|
/**
|
|
@@ -912,7 +925,7 @@ class WebDriver extends Helper {
|
|
|
912
925
|
* @param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
|
|
913
926
|
*/
|
|
914
927
|
async _locateCheckable(locator) {
|
|
915
|
-
return findCheckable.call(this, locator, this.$$.bind(this)).then(res => res)
|
|
928
|
+
return findCheckable.call(this, locator, this.$$.bind(this)).then((res) => res)
|
|
916
929
|
}
|
|
917
930
|
|
|
918
931
|
/**
|
|
@@ -926,8 +939,8 @@ class WebDriver extends Helper {
|
|
|
926
939
|
* @param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
|
|
927
940
|
*/
|
|
928
941
|
async _locateClickable(locator, context) {
|
|
929
|
-
const locateFn = prepareLocateFn.call(this, context)
|
|
930
|
-
return findClickable.call(this, locator, locateFn)
|
|
942
|
+
const locateFn = prepareLocateFn.call(this, context)
|
|
943
|
+
return findClickable.call(this, locator, locateFn)
|
|
931
944
|
}
|
|
932
945
|
|
|
933
946
|
/**
|
|
@@ -940,7 +953,7 @@ class WebDriver extends Helper {
|
|
|
940
953
|
* @param {CodeceptJS.LocatorOrString} locator element located by CSS|XPath|strict locator.
|
|
941
954
|
*/
|
|
942
955
|
async _locateFields(locator) {
|
|
943
|
-
return findFields.call(this, locator).then(res => res)
|
|
956
|
+
return findFields.call(this, locator).then((res) => res)
|
|
944
957
|
}
|
|
945
958
|
|
|
946
959
|
/**
|
|
@@ -948,7 +961,7 @@ class WebDriver extends Helper {
|
|
|
948
961
|
*
|
|
949
962
|
*/
|
|
950
963
|
async grabWebElements(locator) {
|
|
951
|
-
return this._locate(locator)
|
|
964
|
+
return this._locate(locator)
|
|
952
965
|
}
|
|
953
966
|
|
|
954
967
|
/**
|
|
@@ -964,11 +977,11 @@ class WebDriver extends Helper {
|
|
|
964
977
|
* @param {*} timeouts WebDriver timeouts object.
|
|
965
978
|
*/
|
|
966
979
|
defineTimeout(timeouts) {
|
|
967
|
-
return this._defineBrowserTimeout(this.browser, timeouts)
|
|
980
|
+
return this._defineBrowserTimeout(this.browser, timeouts)
|
|
968
981
|
}
|
|
969
982
|
|
|
970
983
|
_defineBrowserTimeout(browser, timeouts) {
|
|
971
|
-
return browser.setTimeout(timeouts)
|
|
984
|
+
return browser.setTimeout(timeouts)
|
|
972
985
|
}
|
|
973
986
|
|
|
974
987
|
/**
|
|
@@ -976,15 +989,15 @@ class WebDriver extends Helper {
|
|
|
976
989
|
*
|
|
977
990
|
*/
|
|
978
991
|
amOnPage(url) {
|
|
979
|
-
let split_url
|
|
992
|
+
let split_url
|
|
980
993
|
if (this.options.basicAuth) {
|
|
981
994
|
if (url.startsWith('/')) {
|
|
982
|
-
url = this.options.url + url
|
|
995
|
+
url = this.options.url + url
|
|
983
996
|
}
|
|
984
|
-
split_url = url.split('//')
|
|
985
|
-
url = `${split_url[0]}//${this.options.basicAuth.username}:${this.options.basicAuth.password}@${split_url[1]}
|
|
997
|
+
split_url = url.split('//')
|
|
998
|
+
url = `${split_url[0]}//${this.options.basicAuth.username}:${this.options.basicAuth.password}@${split_url[1]}`
|
|
986
999
|
}
|
|
987
|
-
return this.browser.url(url)
|
|
1000
|
+
return this.browser.url(url)
|
|
988
1001
|
}
|
|
989
1002
|
|
|
990
1003
|
/**
|
|
@@ -993,18 +1006,18 @@ class WebDriver extends Helper {
|
|
|
993
1006
|
* {{ react }}
|
|
994
1007
|
*/
|
|
995
1008
|
async click(locator, context = null) {
|
|
996
|
-
const clickMethod = this.browser.isMobile && !this.browser.isW3C ? 'touchClick' : 'elementClick'
|
|
997
|
-
const locateFn = prepareLocateFn.call(this, context)
|
|
1009
|
+
const clickMethod = this.browser.isMobile && !this.browser.isW3C ? 'touchClick' : 'elementClick'
|
|
1010
|
+
const locateFn = prepareLocateFn.call(this, context)
|
|
998
1011
|
|
|
999
|
-
const res = await findClickable.call(this, locator, locateFn)
|
|
1012
|
+
const res = await findClickable.call(this, locator, locateFn)
|
|
1000
1013
|
if (context) {
|
|
1001
|
-
assertElementExists(res, locator, 'Clickable element', `was not found inside element ${new Locator(context)}`)
|
|
1014
|
+
assertElementExists(res, locator, 'Clickable element', `was not found inside element ${new Locator(context)}`)
|
|
1002
1015
|
} else {
|
|
1003
|
-
assertElementExists(res, locator, 'Clickable element')
|
|
1016
|
+
assertElementExists(res, locator, 'Clickable element')
|
|
1004
1017
|
}
|
|
1005
|
-
const elem = usingFirstElement(res)
|
|
1006
|
-
highlightActiveElement.call(this, elem)
|
|
1007
|
-
return this.browser[clickMethod](getElementId(elem))
|
|
1018
|
+
const elem = usingFirstElement(res)
|
|
1019
|
+
highlightActiveElement.call(this, elem)
|
|
1020
|
+
return this.browser[clickMethod](getElementId(elem))
|
|
1008
1021
|
}
|
|
1009
1022
|
|
|
1010
1023
|
/**
|
|
@@ -1013,25 +1026,25 @@ class WebDriver extends Helper {
|
|
|
1013
1026
|
* {{ react }}
|
|
1014
1027
|
*/
|
|
1015
1028
|
async forceClick(locator, context = null) {
|
|
1016
|
-
const locateFn = prepareLocateFn.call(this, context)
|
|
1029
|
+
const locateFn = prepareLocateFn.call(this, context)
|
|
1017
1030
|
|
|
1018
|
-
const res = await findClickable.call(this, locator, locateFn)
|
|
1031
|
+
const res = await findClickable.call(this, locator, locateFn)
|
|
1019
1032
|
if (context) {
|
|
1020
|
-
assertElementExists(res, locator, 'Clickable element', `was not found inside element ${new Locator(context)}`)
|
|
1033
|
+
assertElementExists(res, locator, 'Clickable element', `was not found inside element ${new Locator(context)}`)
|
|
1021
1034
|
} else {
|
|
1022
|
-
assertElementExists(res, locator, 'Clickable element')
|
|
1035
|
+
assertElementExists(res, locator, 'Clickable element')
|
|
1023
1036
|
}
|
|
1024
|
-
const elem = usingFirstElement(res)
|
|
1025
|
-
highlightActiveElement.call(this, elem)
|
|
1037
|
+
const elem = usingFirstElement(res)
|
|
1038
|
+
highlightActiveElement.call(this, elem)
|
|
1026
1039
|
|
|
1027
1040
|
return this.executeScript((el) => {
|
|
1028
1041
|
if (document.activeElement instanceof HTMLElement) {
|
|
1029
|
-
document.activeElement.blur()
|
|
1042
|
+
document.activeElement.blur()
|
|
1030
1043
|
}
|
|
1031
|
-
const event = document.createEvent('MouseEvent')
|
|
1032
|
-
event.initEvent('click', true, true)
|
|
1033
|
-
return el.dispatchEvent(event)
|
|
1034
|
-
}, elem)
|
|
1044
|
+
const event = document.createEvent('MouseEvent')
|
|
1045
|
+
event.initEvent('click', true, true)
|
|
1046
|
+
return el.dispatchEvent(event)
|
|
1047
|
+
}, elem)
|
|
1035
1048
|
}
|
|
1036
1049
|
|
|
1037
1050
|
/**
|
|
@@ -1040,18 +1053,18 @@ class WebDriver extends Helper {
|
|
|
1040
1053
|
* {{ react }}
|
|
1041
1054
|
*/
|
|
1042
1055
|
async doubleClick(locator, context = null) {
|
|
1043
|
-
const locateFn = prepareLocateFn.call(this, context)
|
|
1056
|
+
const locateFn = prepareLocateFn.call(this, context)
|
|
1044
1057
|
|
|
1045
|
-
const res = await findClickable.call(this, locator, locateFn)
|
|
1058
|
+
const res = await findClickable.call(this, locator, locateFn)
|
|
1046
1059
|
if (context) {
|
|
1047
|
-
assertElementExists(res, locator, 'Clickable element', `was not found inside element ${new Locator(context)}`)
|
|
1060
|
+
assertElementExists(res, locator, 'Clickable element', `was not found inside element ${new Locator(context)}`)
|
|
1048
1061
|
} else {
|
|
1049
|
-
assertElementExists(res, locator, 'Clickable element')
|
|
1062
|
+
assertElementExists(res, locator, 'Clickable element')
|
|
1050
1063
|
}
|
|
1051
1064
|
|
|
1052
|
-
const elem = usingFirstElement(res)
|
|
1053
|
-
highlightActiveElement.call(this, elem)
|
|
1054
|
-
return elem.doubleClick()
|
|
1065
|
+
const elem = usingFirstElement(res)
|
|
1066
|
+
highlightActiveElement.call(this, elem)
|
|
1067
|
+
return elem.doubleClick()
|
|
1055
1068
|
}
|
|
1056
1069
|
|
|
1057
1070
|
/**
|
|
@@ -1060,24 +1073,24 @@ class WebDriver extends Helper {
|
|
|
1060
1073
|
* {{ react }}
|
|
1061
1074
|
*/
|
|
1062
1075
|
async rightClick(locator, context) {
|
|
1063
|
-
const locateFn = prepareLocateFn.call(this, context)
|
|
1076
|
+
const locateFn = prepareLocateFn.call(this, context)
|
|
1064
1077
|
|
|
1065
|
-
const res = await findClickable.call(this, locator, locateFn)
|
|
1078
|
+
const res = await findClickable.call(this, locator, locateFn)
|
|
1066
1079
|
if (context) {
|
|
1067
|
-
assertElementExists(res, locator, 'Clickable element', `was not found inside element ${new Locator(context)}`)
|
|
1080
|
+
assertElementExists(res, locator, 'Clickable element', `was not found inside element ${new Locator(context)}`)
|
|
1068
1081
|
} else {
|
|
1069
|
-
assertElementExists(res, locator, 'Clickable element')
|
|
1082
|
+
assertElementExists(res, locator, 'Clickable element')
|
|
1070
1083
|
}
|
|
1071
1084
|
|
|
1072
|
-
const el = usingFirstElement(res)
|
|
1085
|
+
const el = usingFirstElement(res)
|
|
1073
1086
|
|
|
1074
|
-
await el.moveTo()
|
|
1087
|
+
await el.moveTo()
|
|
1075
1088
|
|
|
1076
1089
|
if (this.browser.isW3C) {
|
|
1077
|
-
return el.click({ button: 'right' })
|
|
1090
|
+
return el.click({ button: 'right' })
|
|
1078
1091
|
}
|
|
1079
1092
|
// JSON Wire version
|
|
1080
|
-
await this.browser.buttonDown(2)
|
|
1093
|
+
await this.browser.buttonDown(2)
|
|
1081
1094
|
}
|
|
1082
1095
|
|
|
1083
1096
|
/**
|
|
@@ -1086,24 +1099,24 @@ class WebDriver extends Helper {
|
|
|
1086
1099
|
* {{ react }}
|
|
1087
1100
|
*/
|
|
1088
1101
|
async forceRightClick(locator, context = null) {
|
|
1089
|
-
const locateFn = prepareLocateFn.call(this, context)
|
|
1102
|
+
const locateFn = prepareLocateFn.call(this, context)
|
|
1090
1103
|
|
|
1091
|
-
const res = await findClickable.call(this, locator, locateFn)
|
|
1104
|
+
const res = await findClickable.call(this, locator, locateFn)
|
|
1092
1105
|
if (context) {
|
|
1093
|
-
assertElementExists(res, locator, 'Clickable element', `was not found inside element ${new Locator(context)}`)
|
|
1106
|
+
assertElementExists(res, locator, 'Clickable element', `was not found inside element ${new Locator(context)}`)
|
|
1094
1107
|
} else {
|
|
1095
|
-
assertElementExists(res, locator, 'Clickable element')
|
|
1108
|
+
assertElementExists(res, locator, 'Clickable element')
|
|
1096
1109
|
}
|
|
1097
|
-
const elem = usingFirstElement(res)
|
|
1110
|
+
const elem = usingFirstElement(res)
|
|
1098
1111
|
|
|
1099
1112
|
return this.executeScript((el) => {
|
|
1100
1113
|
if (document.activeElement instanceof HTMLElement) {
|
|
1101
|
-
document.activeElement.blur()
|
|
1114
|
+
document.activeElement.blur()
|
|
1102
1115
|
}
|
|
1103
|
-
const event = document.createEvent('MouseEvent')
|
|
1104
|
-
event.initEvent('contextmenu', true, true)
|
|
1105
|
-
return el.dispatchEvent(event)
|
|
1106
|
-
}, elem)
|
|
1116
|
+
const event = document.createEvent('MouseEvent')
|
|
1117
|
+
event.initEvent('contextmenu', true, true)
|
|
1118
|
+
return el.dispatchEvent(event)
|
|
1119
|
+
}, elem)
|
|
1107
1120
|
}
|
|
1108
1121
|
|
|
1109
1122
|
/**
|
|
@@ -1113,12 +1126,12 @@ class WebDriver extends Helper {
|
|
|
1113
1126
|
*
|
|
1114
1127
|
*/
|
|
1115
1128
|
async fillField(field, value) {
|
|
1116
|
-
const res = await findFields.call(this, field)
|
|
1117
|
-
assertElementExists(res, field, 'Field')
|
|
1118
|
-
const elem = usingFirstElement(res)
|
|
1119
|
-
highlightActiveElement.call(this, elem)
|
|
1120
|
-
await elem.clearValue()
|
|
1121
|
-
await elem.setValue(value.toString())
|
|
1129
|
+
const res = await findFields.call(this, field)
|
|
1130
|
+
assertElementExists(res, field, 'Field')
|
|
1131
|
+
const elem = usingFirstElement(res)
|
|
1132
|
+
highlightActiveElement.call(this, elem)
|
|
1133
|
+
await elem.clearValue()
|
|
1134
|
+
await elem.setValue(value.toString())
|
|
1122
1135
|
}
|
|
1123
1136
|
|
|
1124
1137
|
/**
|
|
@@ -1126,15 +1139,15 @@ class WebDriver extends Helper {
|
|
|
1126
1139
|
* {{ react }}
|
|
1127
1140
|
*/
|
|
1128
1141
|
async appendField(field, value) {
|
|
1129
|
-
const res = await findFields.call(this, field)
|
|
1130
|
-
assertElementExists(res, field, 'Field')
|
|
1131
|
-
const elem = usingFirstElement(res)
|
|
1132
|
-
highlightActiveElement.call(this, elem)
|
|
1142
|
+
const res = await findFields.call(this, field)
|
|
1143
|
+
assertElementExists(res, field, 'Field')
|
|
1144
|
+
const elem = usingFirstElement(res)
|
|
1145
|
+
highlightActiveElement.call(this, elem)
|
|
1133
1146
|
if (this.options.automationProtocol) {
|
|
1134
|
-
const curentValue = await elem.getValue()
|
|
1135
|
-
return elem.setValue(curentValue + value.toString())
|
|
1147
|
+
const curentValue = await elem.getValue()
|
|
1148
|
+
return elem.setValue(curentValue + value.toString())
|
|
1136
1149
|
}
|
|
1137
|
-
return elem.addValue(value.toString())
|
|
1150
|
+
return elem.addValue(value.toString())
|
|
1138
1151
|
}
|
|
1139
1152
|
|
|
1140
1153
|
/**
|
|
@@ -1142,47 +1155,63 @@ class WebDriver extends Helper {
|
|
|
1142
1155
|
*
|
|
1143
1156
|
*/
|
|
1144
1157
|
async clearField(field) {
|
|
1145
|
-
const res = await findFields.call(this, field)
|
|
1146
|
-
assertElementExists(res, field, 'Field')
|
|
1147
|
-
const elem = usingFirstElement(res)
|
|
1148
|
-
highlightActiveElement.call(this, elem)
|
|
1158
|
+
const res = await findFields.call(this, field)
|
|
1159
|
+
assertElementExists(res, field, 'Field')
|
|
1160
|
+
const elem = usingFirstElement(res)
|
|
1161
|
+
highlightActiveElement.call(this, elem)
|
|
1149
1162
|
if (this.options.automationProtocol) {
|
|
1150
|
-
return elem.setValue('')
|
|
1163
|
+
return elem.setValue('')
|
|
1151
1164
|
}
|
|
1152
|
-
return elem.clearValue(getElementId(elem))
|
|
1165
|
+
return elem.clearValue(getElementId(elem))
|
|
1153
1166
|
}
|
|
1154
1167
|
|
|
1155
1168
|
/**
|
|
1156
1169
|
* {{> selectOption }}
|
|
1157
1170
|
*/
|
|
1158
1171
|
async selectOption(select, option) {
|
|
1159
|
-
const res = await findFields.call(this, select)
|
|
1160
|
-
assertElementExists(res, select, 'Selectable field')
|
|
1161
|
-
const elem = usingFirstElement(res)
|
|
1162
|
-
highlightActiveElement.call(this, elem)
|
|
1172
|
+
const res = await findFields.call(this, select)
|
|
1173
|
+
assertElementExists(res, select, 'Selectable field')
|
|
1174
|
+
const elem = usingFirstElement(res)
|
|
1175
|
+
highlightActiveElement.call(this, elem)
|
|
1163
1176
|
|
|
1164
1177
|
if (!Array.isArray(option)) {
|
|
1165
|
-
option = [option]
|
|
1178
|
+
option = [option]
|
|
1166
1179
|
}
|
|
1167
1180
|
|
|
1168
1181
|
// select options by visible text
|
|
1169
|
-
let els = await forEachAsync(option, async opt =>
|
|
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
|
+
)
|
|
1170
1189
|
|
|
1171
1190
|
const clickOptionFn = async (el) => {
|
|
1172
|
-
if (el[0]) el = el[0]
|
|
1173
|
-
const elementId = getElementId(el)
|
|
1174
|
-
if (elementId) return this.browser.elementClick(elementId)
|
|
1175
|
-
}
|
|
1191
|
+
if (el[0]) el = el[0]
|
|
1192
|
+
const elementId = getElementId(el)
|
|
1193
|
+
if (elementId) return this.browser.elementClick(elementId)
|
|
1194
|
+
}
|
|
1176
1195
|
|
|
1177
1196
|
if (Array.isArray(els) && els.length) {
|
|
1178
|
-
return forEachAsync(els, clickOptionFn)
|
|
1197
|
+
return forEachAsync(els, clickOptionFn)
|
|
1179
1198
|
}
|
|
1180
1199
|
// select options by value
|
|
1181
|
-
els = await forEachAsync(option, async opt =>
|
|
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
|
+
)
|
|
1182
1207
|
if (els.length === 0) {
|
|
1183
|
-
throw new ElementNotFound(
|
|
1208
|
+
throw new ElementNotFound(
|
|
1209
|
+
select,
|
|
1210
|
+
`Option "${option}" in`,
|
|
1211
|
+
'was not found neither by a visible text nor by a value',
|
|
1212
|
+
)
|
|
1184
1213
|
}
|
|
1185
|
-
return forEachAsync(els, clickOptionFn)
|
|
1214
|
+
return forEachAsync(els, clickOptionFn)
|
|
1186
1215
|
}
|
|
1187
1216
|
|
|
1188
1217
|
/**
|
|
@@ -1191,27 +1220,29 @@ class WebDriver extends Helper {
|
|
|
1191
1220
|
* {{> attachFile }}
|
|
1192
1221
|
*/
|
|
1193
1222
|
async attachFile(locator, pathToFile) {
|
|
1194
|
-
let file = path.join(global.codecept_dir, pathToFile)
|
|
1223
|
+
let file = path.join(global.codecept_dir, pathToFile)
|
|
1195
1224
|
if (!fileExists(file)) {
|
|
1196
|
-
throw new Error(`File at ${file} can not be found on local system`)
|
|
1225
|
+
throw new Error(`File at ${file} can not be found on local system`)
|
|
1197
1226
|
}
|
|
1198
1227
|
|
|
1199
|
-
const res = await findFields.call(this, locator)
|
|
1200
|
-
this.debug(`Uploading ${file}`)
|
|
1201
|
-
assertElementExists(res, locator, 'File field')
|
|
1202
|
-
const el = usingFirstElement(res)
|
|
1228
|
+
const res = await findFields.call(this, locator)
|
|
1229
|
+
this.debug(`Uploading ${file}`)
|
|
1230
|
+
assertElementExists(res, locator, 'File field')
|
|
1231
|
+
const el = usingFirstElement(res)
|
|
1203
1232
|
|
|
1204
1233
|
// Remote Upload (when running Selenium Server)
|
|
1205
1234
|
if (this.options.remoteFileUpload && !this.options.automationProtocol) {
|
|
1206
1235
|
try {
|
|
1207
|
-
this.debugSection('File', 'Uploading file to remote server')
|
|
1208
|
-
file = await this.browser.uploadFile(file)
|
|
1236
|
+
this.debugSection('File', 'Uploading file to remote server')
|
|
1237
|
+
file = await this.browser.uploadFile(file)
|
|
1209
1238
|
} catch (err) {
|
|
1210
|
-
throw new Error(
|
|
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
|
+
)
|
|
1211
1242
|
}
|
|
1212
1243
|
}
|
|
1213
1244
|
|
|
1214
|
-
return el.addValue(file)
|
|
1245
|
+
return el.addValue(file)
|
|
1215
1246
|
}
|
|
1216
1247
|
|
|
1217
1248
|
/**
|
|
@@ -1219,19 +1250,19 @@ class WebDriver extends Helper {
|
|
|
1219
1250
|
* {{> checkOption }}
|
|
1220
1251
|
*/
|
|
1221
1252
|
async checkOption(field, context = null) {
|
|
1222
|
-
const clickMethod = this.browser.isMobile && !this.browser.isW3C ? 'touchClick' : 'elementClick'
|
|
1223
|
-
const locateFn = prepareLocateFn.call(this, context)
|
|
1253
|
+
const clickMethod = this.browser.isMobile && !this.browser.isW3C ? 'touchClick' : 'elementClick'
|
|
1254
|
+
const locateFn = prepareLocateFn.call(this, context)
|
|
1224
1255
|
|
|
1225
|
-
const res = await findCheckable.call(this, field, locateFn)
|
|
1256
|
+
const res = await findCheckable.call(this, field, locateFn)
|
|
1226
1257
|
|
|
1227
|
-
assertElementExists(res, field, 'Checkable')
|
|
1228
|
-
const elem = usingFirstElement(res)
|
|
1229
|
-
const elementId = getElementId(elem)
|
|
1230
|
-
highlightActiveElement.call(this, elem)
|
|
1258
|
+
assertElementExists(res, field, 'Checkable')
|
|
1259
|
+
const elem = usingFirstElement(res)
|
|
1260
|
+
const elementId = getElementId(elem)
|
|
1261
|
+
highlightActiveElement.call(this, elem)
|
|
1231
1262
|
|
|
1232
|
-
const isSelected = await this.browser.isElementSelected(elementId)
|
|
1233
|
-
if (isSelected) return Promise.resolve(true)
|
|
1234
|
-
return this.browser[clickMethod](elementId)
|
|
1263
|
+
const isSelected = await this.browser.isElementSelected(elementId)
|
|
1264
|
+
if (isSelected) return Promise.resolve(true)
|
|
1265
|
+
return this.browser[clickMethod](elementId)
|
|
1235
1266
|
}
|
|
1236
1267
|
|
|
1237
1268
|
/**
|
|
@@ -1239,19 +1270,19 @@ class WebDriver extends Helper {
|
|
|
1239
1270
|
* {{> uncheckOption }}
|
|
1240
1271
|
*/
|
|
1241
1272
|
async uncheckOption(field, context = null) {
|
|
1242
|
-
const clickMethod = this.browser.isMobile && !this.browser.isW3C ? 'touchClick' : 'elementClick'
|
|
1243
|
-
const locateFn = prepareLocateFn.call(this, context)
|
|
1273
|
+
const clickMethod = this.browser.isMobile && !this.browser.isW3C ? 'touchClick' : 'elementClick'
|
|
1274
|
+
const locateFn = prepareLocateFn.call(this, context)
|
|
1244
1275
|
|
|
1245
|
-
const res = await findCheckable.call(this, field, locateFn)
|
|
1276
|
+
const res = await findCheckable.call(this, field, locateFn)
|
|
1246
1277
|
|
|
1247
|
-
assertElementExists(res, field, 'Checkable')
|
|
1248
|
-
const elem = usingFirstElement(res)
|
|
1249
|
-
const elementId = getElementId(elem)
|
|
1250
|
-
highlightActiveElement.call(this, elem)
|
|
1278
|
+
assertElementExists(res, field, 'Checkable')
|
|
1279
|
+
const elem = usingFirstElement(res)
|
|
1280
|
+
const elementId = getElementId(elem)
|
|
1281
|
+
highlightActiveElement.call(this, elem)
|
|
1251
1282
|
|
|
1252
|
-
const isSelected = await this.browser.isElementSelected(elementId)
|
|
1253
|
-
if (!isSelected) return Promise.resolve(true)
|
|
1254
|
-
return this.browser[clickMethod](elementId)
|
|
1283
|
+
const isSelected = await this.browser.isElementSelected(elementId)
|
|
1284
|
+
if (!isSelected) return Promise.resolve(true)
|
|
1285
|
+
return this.browser[clickMethod](elementId)
|
|
1255
1286
|
}
|
|
1256
1287
|
|
|
1257
1288
|
/**
|
|
@@ -1259,10 +1290,10 @@ class WebDriver extends Helper {
|
|
|
1259
1290
|
*
|
|
1260
1291
|
*/
|
|
1261
1292
|
async grabTextFromAll(locator) {
|
|
1262
|
-
const res = await this._locate(locator, true)
|
|
1263
|
-
const val = await forEachAsync(res, el => this.browser.getElementText(getElementId(el)))
|
|
1264
|
-
this.debugSection('GrabText', String(val))
|
|
1265
|
-
return val
|
|
1293
|
+
const res = await this._locate(locator, true)
|
|
1294
|
+
const val = await forEachAsync(res, (el) => this.browser.getElementText(getElementId(el)))
|
|
1295
|
+
this.debugSection('GrabText', String(val))
|
|
1296
|
+
return val
|
|
1266
1297
|
}
|
|
1267
1298
|
|
|
1268
1299
|
/**
|
|
@@ -1270,13 +1301,13 @@ class WebDriver extends Helper {
|
|
|
1270
1301
|
*
|
|
1271
1302
|
*/
|
|
1272
1303
|
async grabTextFrom(locator) {
|
|
1273
|
-
const texts = await this.grabTextFromAll(locator)
|
|
1274
|
-
assertElementExists(texts, locator)
|
|
1304
|
+
const texts = await this.grabTextFromAll(locator)
|
|
1305
|
+
assertElementExists(texts, locator)
|
|
1275
1306
|
if (texts.length > 1) {
|
|
1276
|
-
this.debugSection('GrabText', `Using first element out of ${texts.length}`)
|
|
1307
|
+
this.debugSection('GrabText', `Using first element out of ${texts.length}`)
|
|
1277
1308
|
}
|
|
1278
1309
|
|
|
1279
|
-
return texts[0]
|
|
1310
|
+
return texts[0]
|
|
1280
1311
|
}
|
|
1281
1312
|
|
|
1282
1313
|
/**
|
|
@@ -1284,10 +1315,10 @@ class WebDriver extends Helper {
|
|
|
1284
1315
|
*
|
|
1285
1316
|
*/
|
|
1286
1317
|
async grabHTMLFromAll(locator) {
|
|
1287
|
-
const elems = await this._locate(locator, true)
|
|
1288
|
-
const html = await forEachAsync(elems, elem => elem.getHTML(false))
|
|
1289
|
-
this.debugSection('GrabHTML', String(html))
|
|
1290
|
-
return html
|
|
1318
|
+
const elems = await this._locate(locator, true)
|
|
1319
|
+
const html = await forEachAsync(elems, (elem) => elem.getHTML(false))
|
|
1320
|
+
this.debugSection('GrabHTML', String(html))
|
|
1321
|
+
return html
|
|
1291
1322
|
}
|
|
1292
1323
|
|
|
1293
1324
|
/**
|
|
@@ -1295,13 +1326,13 @@ class WebDriver extends Helper {
|
|
|
1295
1326
|
*
|
|
1296
1327
|
*/
|
|
1297
1328
|
async grabHTMLFrom(locator) {
|
|
1298
|
-
const html = await this.grabHTMLFromAll(locator)
|
|
1299
|
-
assertElementExists(html, locator)
|
|
1329
|
+
const html = await this.grabHTMLFromAll(locator)
|
|
1330
|
+
assertElementExists(html, locator)
|
|
1300
1331
|
if (html.length > 1) {
|
|
1301
|
-
this.debugSection('GrabHTML', `Using first element out of ${html.length}`)
|
|
1332
|
+
this.debugSection('GrabHTML', `Using first element out of ${html.length}`)
|
|
1302
1333
|
}
|
|
1303
1334
|
|
|
1304
|
-
return html[0]
|
|
1335
|
+
return html[0]
|
|
1305
1336
|
}
|
|
1306
1337
|
|
|
1307
1338
|
/**
|
|
@@ -1309,11 +1340,11 @@ class WebDriver extends Helper {
|
|
|
1309
1340
|
*
|
|
1310
1341
|
*/
|
|
1311
1342
|
async grabValueFromAll(locator) {
|
|
1312
|
-
const res = await this._locate(locator, true)
|
|
1313
|
-
const val = await forEachAsync(res, el => el.getValue())
|
|
1314
|
-
this.debugSection('GrabValue', String(val))
|
|
1343
|
+
const res = await this._locate(locator, true)
|
|
1344
|
+
const val = await forEachAsync(res, (el) => el.getValue())
|
|
1345
|
+
this.debugSection('GrabValue', String(val))
|
|
1315
1346
|
|
|
1316
|
-
return val
|
|
1347
|
+
return val
|
|
1317
1348
|
}
|
|
1318
1349
|
|
|
1319
1350
|
/**
|
|
@@ -1321,92 +1352,92 @@ class WebDriver extends Helper {
|
|
|
1321
1352
|
*
|
|
1322
1353
|
*/
|
|
1323
1354
|
async grabValueFrom(locator) {
|
|
1324
|
-
const values = await this.grabValueFromAll(locator)
|
|
1325
|
-
assertElementExists(values, locator)
|
|
1355
|
+
const values = await this.grabValueFromAll(locator)
|
|
1356
|
+
assertElementExists(values, locator)
|
|
1326
1357
|
if (values.length > 1) {
|
|
1327
|
-
this.debugSection('GrabValue', `Using first element out of ${values.length}`)
|
|
1358
|
+
this.debugSection('GrabValue', `Using first element out of ${values.length}`)
|
|
1328
1359
|
}
|
|
1329
1360
|
|
|
1330
|
-
return values[0]
|
|
1361
|
+
return values[0]
|
|
1331
1362
|
}
|
|
1332
1363
|
|
|
1333
1364
|
/**
|
|
1334
1365
|
* {{> grabCssPropertyFromAll }}
|
|
1335
1366
|
*/
|
|
1336
1367
|
async grabCssPropertyFromAll(locator, cssProperty) {
|
|
1337
|
-
const res = await this._locate(locator, true)
|
|
1338
|
-
const val = await forEachAsync(res, async el => this.browser.getElementCSSValue(getElementId(el), cssProperty))
|
|
1339
|
-
this.debugSection('Grab', String(val))
|
|
1340
|
-
return val
|
|
1368
|
+
const res = await this._locate(locator, true)
|
|
1369
|
+
const val = await forEachAsync(res, async (el) => this.browser.getElementCSSValue(getElementId(el), cssProperty))
|
|
1370
|
+
this.debugSection('Grab', String(val))
|
|
1371
|
+
return val
|
|
1341
1372
|
}
|
|
1342
1373
|
|
|
1343
1374
|
/**
|
|
1344
1375
|
* {{> grabCssPropertyFrom }}
|
|
1345
1376
|
*/
|
|
1346
1377
|
async grabCssPropertyFrom(locator, cssProperty) {
|
|
1347
|
-
const cssValues = await this.grabCssPropertyFromAll(locator, cssProperty)
|
|
1348
|
-
assertElementExists(cssValues, locator)
|
|
1378
|
+
const cssValues = await this.grabCssPropertyFromAll(locator, cssProperty)
|
|
1379
|
+
assertElementExists(cssValues, locator)
|
|
1349
1380
|
|
|
1350
1381
|
if (cssValues.length > 1) {
|
|
1351
|
-
this.debugSection('GrabCSS', `Using first element out of ${cssValues.length}`)
|
|
1382
|
+
this.debugSection('GrabCSS', `Using first element out of ${cssValues.length}`)
|
|
1352
1383
|
}
|
|
1353
1384
|
|
|
1354
|
-
return cssValues[0]
|
|
1385
|
+
return cssValues[0]
|
|
1355
1386
|
}
|
|
1356
1387
|
|
|
1357
1388
|
/**
|
|
1358
1389
|
* {{> grabAttributeFromAll }}
|
|
1359
1390
|
*/
|
|
1360
1391
|
async grabAttributeFromAll(locator, attr) {
|
|
1361
|
-
const res = await this._locate(locator, true)
|
|
1362
|
-
const val = await forEachAsync(res, async el => el.getAttribute(attr))
|
|
1363
|
-
this.debugSection('GrabAttribute', String(val))
|
|
1364
|
-
return val
|
|
1392
|
+
const res = await this._locate(locator, true)
|
|
1393
|
+
const val = await forEachAsync(res, async (el) => el.getAttribute(attr))
|
|
1394
|
+
this.debugSection('GrabAttribute', String(val))
|
|
1395
|
+
return val
|
|
1365
1396
|
}
|
|
1366
1397
|
|
|
1367
1398
|
/**
|
|
1368
1399
|
* {{> grabAttributeFrom }}
|
|
1369
1400
|
*/
|
|
1370
1401
|
async grabAttributeFrom(locator, attr) {
|
|
1371
|
-
const attrs = await this.grabAttributeFromAll(locator, attr)
|
|
1372
|
-
assertElementExists(attrs, locator)
|
|
1402
|
+
const attrs = await this.grabAttributeFromAll(locator, attr)
|
|
1403
|
+
assertElementExists(attrs, locator)
|
|
1373
1404
|
if (attrs.length > 1) {
|
|
1374
|
-
this.debugSection('GrabAttribute', `Using first element out of ${attrs.length}`)
|
|
1405
|
+
this.debugSection('GrabAttribute', `Using first element out of ${attrs.length}`)
|
|
1375
1406
|
}
|
|
1376
|
-
return attrs[0]
|
|
1407
|
+
return attrs[0]
|
|
1377
1408
|
}
|
|
1378
1409
|
|
|
1379
1410
|
/**
|
|
1380
1411
|
* {{> seeInTitle }}
|
|
1381
1412
|
*/
|
|
1382
1413
|
async seeInTitle(text) {
|
|
1383
|
-
const title = await this.browser.getTitle()
|
|
1384
|
-
return stringIncludes('web page title').assert(text, title)
|
|
1414
|
+
const title = await this.browser.getTitle()
|
|
1415
|
+
return stringIncludes('web page title').assert(text, title)
|
|
1385
1416
|
}
|
|
1386
1417
|
|
|
1387
1418
|
/**
|
|
1388
1419
|
* {{> seeTitleEquals }}
|
|
1389
1420
|
*/
|
|
1390
1421
|
async seeTitleEquals(text) {
|
|
1391
|
-
const title = await this.browser.getTitle()
|
|
1392
|
-
return assert.equal(title, text, `expected web page title to be ${text}, but found ${title}`)
|
|
1422
|
+
const title = await this.browser.getTitle()
|
|
1423
|
+
return assert.equal(title, text, `expected web page title to be ${text}, but found ${title}`)
|
|
1393
1424
|
}
|
|
1394
1425
|
|
|
1395
1426
|
/**
|
|
1396
1427
|
* {{> dontSeeInTitle }}
|
|
1397
1428
|
*/
|
|
1398
1429
|
async dontSeeInTitle(text) {
|
|
1399
|
-
const title = await this.browser.getTitle()
|
|
1400
|
-
return stringIncludes('web page title').negate(text, title)
|
|
1430
|
+
const title = await this.browser.getTitle()
|
|
1431
|
+
return stringIncludes('web page title').negate(text, title)
|
|
1401
1432
|
}
|
|
1402
1433
|
|
|
1403
1434
|
/**
|
|
1404
1435
|
* {{> grabTitle }}
|
|
1405
1436
|
*/
|
|
1406
1437
|
async grabTitle() {
|
|
1407
|
-
const title = await this.browser.getTitle()
|
|
1408
|
-
this.debugSection('Title', title)
|
|
1409
|
-
return title
|
|
1438
|
+
const title = await this.browser.getTitle()
|
|
1439
|
+
this.debugSection('Title', title)
|
|
1440
|
+
return title
|
|
1410
1441
|
}
|
|
1411
1442
|
|
|
1412
1443
|
/**
|
|
@@ -1415,14 +1446,14 @@ class WebDriver extends Helper {
|
|
|
1415
1446
|
* {{ react }}
|
|
1416
1447
|
*/
|
|
1417
1448
|
async see(text, context = null) {
|
|
1418
|
-
return proceedSee.call(this, 'assert', text, context)
|
|
1449
|
+
return proceedSee.call(this, 'assert', text, context)
|
|
1419
1450
|
}
|
|
1420
1451
|
|
|
1421
1452
|
/**
|
|
1422
1453
|
* {{> seeTextEquals }}
|
|
1423
1454
|
*/
|
|
1424
1455
|
async seeTextEquals(text, context = null) {
|
|
1425
|
-
return proceedSee.call(this, 'assert', text, context, true)
|
|
1456
|
+
return proceedSee.call(this, 'assert', text, context, true)
|
|
1426
1457
|
}
|
|
1427
1458
|
|
|
1428
1459
|
/**
|
|
@@ -1431,7 +1462,7 @@ class WebDriver extends Helper {
|
|
|
1431
1462
|
* {{ react }}
|
|
1432
1463
|
*/
|
|
1433
1464
|
async dontSee(text, context = null) {
|
|
1434
|
-
return proceedSee.call(this, 'negate', text, context)
|
|
1465
|
+
return proceedSee.call(this, 'negate', text, context)
|
|
1435
1466
|
}
|
|
1436
1467
|
|
|
1437
1468
|
/**
|
|
@@ -1439,8 +1470,8 @@ class WebDriver extends Helper {
|
|
|
1439
1470
|
*
|
|
1440
1471
|
*/
|
|
1441
1472
|
async seeInField(field, value) {
|
|
1442
|
-
const _value =
|
|
1443
|
-
return proceedSeeField.call(this, 'assert', field, _value)
|
|
1473
|
+
const _value = typeof value === 'boolean' ? value : value.toString()
|
|
1474
|
+
return proceedSeeField.call(this, 'assert', field, _value)
|
|
1444
1475
|
}
|
|
1445
1476
|
|
|
1446
1477
|
/**
|
|
@@ -1448,8 +1479,8 @@ class WebDriver extends Helper {
|
|
|
1448
1479
|
*
|
|
1449
1480
|
*/
|
|
1450
1481
|
async dontSeeInField(field, value) {
|
|
1451
|
-
const _value =
|
|
1452
|
-
return proceedSeeField.call(this, 'negate', field, _value)
|
|
1482
|
+
const _value = typeof value === 'boolean' ? value : value.toString()
|
|
1483
|
+
return proceedSeeField.call(this, 'negate', field, _value)
|
|
1453
1484
|
}
|
|
1454
1485
|
|
|
1455
1486
|
/**
|
|
@@ -1457,7 +1488,7 @@ class WebDriver extends Helper {
|
|
|
1457
1488
|
* {{> seeCheckboxIsChecked }}
|
|
1458
1489
|
*/
|
|
1459
1490
|
async seeCheckboxIsChecked(field) {
|
|
1460
|
-
return proceedSeeCheckbox.call(this, 'assert', field)
|
|
1491
|
+
return proceedSeeCheckbox.call(this, 'assert', field)
|
|
1461
1492
|
}
|
|
1462
1493
|
|
|
1463
1494
|
/**
|
|
@@ -1465,7 +1496,7 @@ class WebDriver extends Helper {
|
|
|
1465
1496
|
* {{> dontSeeCheckboxIsChecked }}
|
|
1466
1497
|
*/
|
|
1467
1498
|
async dontSeeCheckboxIsChecked(field) {
|
|
1468
|
-
return proceedSeeCheckbox.call(this, 'negate', field)
|
|
1499
|
+
return proceedSeeCheckbox.call(this, 'negate', field)
|
|
1469
1500
|
}
|
|
1470
1501
|
|
|
1471
1502
|
/**
|
|
@@ -1474,13 +1505,13 @@ class WebDriver extends Helper {
|
|
|
1474
1505
|
*
|
|
1475
1506
|
*/
|
|
1476
1507
|
async seeElement(locator) {
|
|
1477
|
-
const res = await this._locate(locator, true)
|
|
1478
|
-
assertElementExists(res, locator)
|
|
1479
|
-
const selected = await forEachAsync(res, async el => el.isDisplayed())
|
|
1508
|
+
const res = await this._locate(locator, true)
|
|
1509
|
+
assertElementExists(res, locator)
|
|
1510
|
+
const selected = await forEachAsync(res, async (el) => el.isDisplayed())
|
|
1480
1511
|
try {
|
|
1481
|
-
return truth(`elements of ${
|
|
1512
|
+
return truth(`elements of ${new Locator(locator)}`, 'to be seen').assert(selected)
|
|
1482
1513
|
} catch (e) {
|
|
1483
|
-
dontSeeElementError(locator)
|
|
1514
|
+
dontSeeElementError(locator)
|
|
1484
1515
|
}
|
|
1485
1516
|
}
|
|
1486
1517
|
|
|
@@ -1489,15 +1520,15 @@ class WebDriver extends Helper {
|
|
|
1489
1520
|
* {{ react }}
|
|
1490
1521
|
*/
|
|
1491
1522
|
async dontSeeElement(locator) {
|
|
1492
|
-
const res = await this._locate(locator, false)
|
|
1523
|
+
const res = await this._locate(locator, false)
|
|
1493
1524
|
if (!res || res.length === 0) {
|
|
1494
|
-
return truth(`elements of ${
|
|
1525
|
+
return truth(`elements of ${new Locator(locator)}`, 'to be seen').negate(false)
|
|
1495
1526
|
}
|
|
1496
|
-
const selected = await forEachAsync(res, async el => el.isDisplayed())
|
|
1527
|
+
const selected = await forEachAsync(res, async (el) => el.isDisplayed())
|
|
1497
1528
|
try {
|
|
1498
|
-
return truth(`elements of ${
|
|
1529
|
+
return truth(`elements of ${new Locator(locator)}`, 'to be seen').negate(selected)
|
|
1499
1530
|
} catch (e) {
|
|
1500
|
-
seeElementError(locator)
|
|
1531
|
+
seeElementError(locator)
|
|
1501
1532
|
}
|
|
1502
1533
|
}
|
|
1503
1534
|
|
|
@@ -1506,11 +1537,11 @@ class WebDriver extends Helper {
|
|
|
1506
1537
|
*
|
|
1507
1538
|
*/
|
|
1508
1539
|
async seeElementInDOM(locator) {
|
|
1509
|
-
const res = await this._res(locator)
|
|
1540
|
+
const res = await this._res(locator)
|
|
1510
1541
|
try {
|
|
1511
|
-
return empty('elements').negate(res)
|
|
1542
|
+
return empty('elements').negate(res)
|
|
1512
1543
|
} catch (e) {
|
|
1513
|
-
dontSeeElementInDOMError(locator)
|
|
1544
|
+
dontSeeElementInDOMError(locator)
|
|
1514
1545
|
}
|
|
1515
1546
|
}
|
|
1516
1547
|
|
|
@@ -1519,11 +1550,11 @@ class WebDriver extends Helper {
|
|
|
1519
1550
|
*
|
|
1520
1551
|
*/
|
|
1521
1552
|
async dontSeeElementInDOM(locator) {
|
|
1522
|
-
const res = await this._res(locator)
|
|
1553
|
+
const res = await this._res(locator)
|
|
1523
1554
|
try {
|
|
1524
|
-
return empty('elements').assert(res)
|
|
1555
|
+
return empty('elements').assert(res)
|
|
1525
1556
|
} catch (e) {
|
|
1526
|
-
seeElementInDOMError(locator)
|
|
1557
|
+
seeElementInDOMError(locator)
|
|
1527
1558
|
}
|
|
1528
1559
|
}
|
|
1529
1560
|
|
|
@@ -1532,8 +1563,8 @@ class WebDriver extends Helper {
|
|
|
1532
1563
|
*
|
|
1533
1564
|
*/
|
|
1534
1565
|
async seeInSource(text) {
|
|
1535
|
-
const source = await this.browser.getPageSource()
|
|
1536
|
-
return stringIncludes('HTML source of a page').assert(text, source)
|
|
1566
|
+
const source = await this.browser.getPageSource()
|
|
1567
|
+
return stringIncludes('HTML source of a page').assert(text, source)
|
|
1537
1568
|
}
|
|
1538
1569
|
|
|
1539
1570
|
/**
|
|
@@ -1541,7 +1572,7 @@ class WebDriver extends Helper {
|
|
|
1541
1572
|
*
|
|
1542
1573
|
*/
|
|
1543
1574
|
async grabSource() {
|
|
1544
|
-
return this.browser.getPageSource()
|
|
1575
|
+
return this.browser.getPageSource()
|
|
1545
1576
|
}
|
|
1546
1577
|
|
|
1547
1578
|
/**
|
|
@@ -1549,27 +1580,27 @@ class WebDriver extends Helper {
|
|
|
1549
1580
|
*/
|
|
1550
1581
|
async grabBrowserLogs() {
|
|
1551
1582
|
if (this.browser.isW3C) {
|
|
1552
|
-
this.debug('Logs not available in W3C specification')
|
|
1553
|
-
return
|
|
1583
|
+
this.debug('Logs not available in W3C specification')
|
|
1584
|
+
return
|
|
1554
1585
|
}
|
|
1555
|
-
return this.browser.getLogs('browser')
|
|
1586
|
+
return this.browser.getLogs('browser')
|
|
1556
1587
|
}
|
|
1557
1588
|
|
|
1558
1589
|
/**
|
|
1559
1590
|
* {{> grabCurrentUrl }}
|
|
1560
1591
|
*/
|
|
1561
1592
|
async grabCurrentUrl() {
|
|
1562
|
-
const res = await this.browser.getUrl()
|
|
1563
|
-
this.debugSection('Url', res)
|
|
1564
|
-
return res
|
|
1593
|
+
const res = await this.browser.getUrl()
|
|
1594
|
+
this.debugSection('Url', res)
|
|
1595
|
+
return res
|
|
1565
1596
|
}
|
|
1566
1597
|
|
|
1567
1598
|
/**
|
|
1568
1599
|
* {{> dontSeeInSource }}
|
|
1569
1600
|
*/
|
|
1570
1601
|
async dontSeeInSource(text) {
|
|
1571
|
-
const source = await this.browser.getPageSource()
|
|
1572
|
-
return stringIncludes('HTML source of a page').negate(text, source)
|
|
1602
|
+
const source = await this.browser.getPageSource()
|
|
1603
|
+
return stringIncludes('HTML source of a page').negate(text, source)
|
|
1573
1604
|
}
|
|
1574
1605
|
|
|
1575
1606
|
/**
|
|
@@ -1577,8 +1608,12 @@ class WebDriver extends Helper {
|
|
|
1577
1608
|
* {{ react }}
|
|
1578
1609
|
*/
|
|
1579
1610
|
async seeNumberOfElements(locator, num) {
|
|
1580
|
-
const res = await this._locate(locator)
|
|
1581
|
-
return assert.equal(
|
|
1611
|
+
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
|
+
)
|
|
1582
1617
|
}
|
|
1583
1618
|
|
|
1584
1619
|
/**
|
|
@@ -1586,86 +1621,93 @@ class WebDriver extends Helper {
|
|
|
1586
1621
|
* {{ react }}
|
|
1587
1622
|
*/
|
|
1588
1623
|
async seeNumberOfVisibleElements(locator, num) {
|
|
1589
|
-
const res = await this.grabNumberOfVisibleElements(locator)
|
|
1590
|
-
return assert.equal(
|
|
1624
|
+
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
|
+
)
|
|
1591
1630
|
}
|
|
1592
1631
|
|
|
1593
1632
|
/**
|
|
1594
1633
|
* {{> seeCssPropertiesOnElements }}
|
|
1595
1634
|
*/
|
|
1596
1635
|
async seeCssPropertiesOnElements(locator, cssProperties) {
|
|
1597
|
-
const res = await this._locate(locator)
|
|
1598
|
-
assertElementExists(res, locator)
|
|
1636
|
+
const res = await this._locate(locator)
|
|
1637
|
+
assertElementExists(res, locator)
|
|
1599
1638
|
|
|
1600
|
-
const cssPropertiesCamelCase = convertCssPropertiesToCamelCase(cssProperties)
|
|
1601
|
-
const elemAmount = res.length
|
|
1602
|
-
let props = []
|
|
1639
|
+
const cssPropertiesCamelCase = convertCssPropertiesToCamelCase(cssProperties)
|
|
1640
|
+
const elemAmount = res.length
|
|
1641
|
+
let props = []
|
|
1603
1642
|
|
|
1604
1643
|
for (const element of res) {
|
|
1605
1644
|
for (const prop of Object.keys(cssProperties)) {
|
|
1606
|
-
const cssProp = await this.grabCssPropertyFrom(locator, prop)
|
|
1645
|
+
const cssProp = await this.grabCssPropertyFrom(locator, prop)
|
|
1607
1646
|
if (isColorProperty(prop)) {
|
|
1608
|
-
props.push(convertColorToRGBA(cssProp))
|
|
1647
|
+
props.push(convertColorToRGBA(cssProp))
|
|
1609
1648
|
} else {
|
|
1610
|
-
props.push(cssProp)
|
|
1649
|
+
props.push(cssProp)
|
|
1611
1650
|
}
|
|
1612
1651
|
}
|
|
1613
1652
|
}
|
|
1614
1653
|
|
|
1615
|
-
const values = Object.keys(cssPropertiesCamelCase).map(key => cssPropertiesCamelCase[key])
|
|
1616
|
-
if (!Array.isArray(props)) props = [props]
|
|
1617
|
-
let chunked = chunkArray(props, values.length)
|
|
1654
|
+
const values = Object.keys(cssPropertiesCamelCase).map((key) => cssPropertiesCamelCase[key])
|
|
1655
|
+
if (!Array.isArray(props)) props = [props]
|
|
1656
|
+
let chunked = chunkArray(props, values.length)
|
|
1618
1657
|
chunked = chunked.filter((val) => {
|
|
1619
1658
|
for (let i = 0; i < val.length; ++i) {
|
|
1620
1659
|
// eslint-disable-next-line eqeqeq
|
|
1621
|
-
if (val[i] != values[i]) return false
|
|
1660
|
+
if (val[i] != values[i]) return false
|
|
1622
1661
|
}
|
|
1623
|
-
return true
|
|
1624
|
-
})
|
|
1625
|
-
return equals(
|
|
1662
|
+
return true
|
|
1663
|
+
})
|
|
1664
|
+
return equals(
|
|
1665
|
+
`all elements (${new Locator(locator)}) to have CSS property ${JSON.stringify(cssProperties)}`,
|
|
1666
|
+
).assert(chunked.length, elemAmount)
|
|
1626
1667
|
}
|
|
1627
1668
|
|
|
1628
1669
|
/**
|
|
1629
1670
|
* {{> seeAttributesOnElements }}
|
|
1630
1671
|
*/
|
|
1631
1672
|
async seeAttributesOnElements(locator, attributes) {
|
|
1632
|
-
const res = await this._locate(locator)
|
|
1633
|
-
assertElementExists(res, locator)
|
|
1634
|
-
const elemAmount = res.length
|
|
1673
|
+
const res = await this._locate(locator)
|
|
1674
|
+
assertElementExists(res, locator)
|
|
1675
|
+
const elemAmount = res.length
|
|
1635
1676
|
|
|
1636
1677
|
let attrs = await forEachAsync(res, async (el) => {
|
|
1637
|
-
return forEachAsync(Object.keys(attributes), async attr => el.getAttribute(attr))
|
|
1638
|
-
})
|
|
1678
|
+
return forEachAsync(Object.keys(attributes), async (attr) => el.getAttribute(attr))
|
|
1679
|
+
})
|
|
1639
1680
|
|
|
1640
|
-
const values = Object.keys(attributes).map(key => attributes[key])
|
|
1641
|
-
if (!Array.isArray(attrs)) attrs = [attrs]
|
|
1642
|
-
let chunked = chunkArray(attrs, values.length)
|
|
1681
|
+
const values = Object.keys(attributes).map((key) => attributes[key])
|
|
1682
|
+
if (!Array.isArray(attrs)) attrs = [attrs]
|
|
1683
|
+
let chunked = chunkArray(attrs, values.length)
|
|
1643
1684
|
chunked = chunked.filter((val) => {
|
|
1644
1685
|
for (let i = 0; i < val.length; ++i) {
|
|
1645
|
-
const _actual = Number.isNaN(val[i]) ||
|
|
1646
|
-
const _expected =
|
|
1686
|
+
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)
|
|
1647
1689
|
// the attribute could be a boolean
|
|
1648
|
-
if (typeof _actual === 'boolean') return _actual === _expected
|
|
1649
|
-
if (_actual !== _expected) return false
|
|
1690
|
+
if (typeof _actual === 'boolean') return _actual === _expected
|
|
1691
|
+
if (_actual !== _expected) return false
|
|
1650
1692
|
}
|
|
1651
|
-
return true
|
|
1652
|
-
})
|
|
1693
|
+
return true
|
|
1694
|
+
})
|
|
1653
1695
|
return assert.ok(
|
|
1654
1696
|
chunked.length === elemAmount,
|
|
1655
|
-
`expected all elements (${
|
|
1656
|
-
)
|
|
1697
|
+
`expected all elements (${new Locator(locator)}) to have attributes ${JSON.stringify(attributes)}`,
|
|
1698
|
+
)
|
|
1657
1699
|
}
|
|
1658
1700
|
|
|
1659
1701
|
/**
|
|
1660
1702
|
* {{> grabNumberOfVisibleElements }}
|
|
1661
1703
|
*/
|
|
1662
1704
|
async grabNumberOfVisibleElements(locator) {
|
|
1663
|
-
const res = await this._locate(locator)
|
|
1705
|
+
const res = await this._locate(locator)
|
|
1664
1706
|
|
|
1665
|
-
let selected = await forEachAsync(res, async el => el.isDisplayed())
|
|
1666
|
-
if (!Array.isArray(selected)) selected = [selected]
|
|
1667
|
-
selected = selected.filter(val => val === true)
|
|
1668
|
-
return selected.length
|
|
1707
|
+
let selected = await forEachAsync(res, async (el) => el.isDisplayed())
|
|
1708
|
+
if (!Array.isArray(selected)) selected = [selected]
|
|
1709
|
+
selected = selected.filter((val) => val === true)
|
|
1710
|
+
return selected.length
|
|
1669
1711
|
}
|
|
1670
1712
|
|
|
1671
1713
|
/**
|
|
@@ -1673,8 +1715,8 @@ class WebDriver extends Helper {
|
|
|
1673
1715
|
*
|
|
1674
1716
|
*/
|
|
1675
1717
|
async seeInCurrentUrl(url) {
|
|
1676
|
-
const res = await this.browser.getUrl()
|
|
1677
|
-
return stringIncludes('url').assert(url, decodeUrl(res))
|
|
1718
|
+
const res = await this.browser.getUrl()
|
|
1719
|
+
return stringIncludes('url').assert(url, decodeUrl(res))
|
|
1678
1720
|
}
|
|
1679
1721
|
|
|
1680
1722
|
/**
|
|
@@ -1682,8 +1724,8 @@ class WebDriver extends Helper {
|
|
|
1682
1724
|
*
|
|
1683
1725
|
*/
|
|
1684
1726
|
async dontSeeInCurrentUrl(url) {
|
|
1685
|
-
const res = await this.browser.getUrl()
|
|
1686
|
-
return stringIncludes('url').negate(url, decodeUrl(res))
|
|
1727
|
+
const res = await this.browser.getUrl()
|
|
1728
|
+
return stringIncludes('url').negate(url, decodeUrl(res))
|
|
1687
1729
|
}
|
|
1688
1730
|
|
|
1689
1731
|
/**
|
|
@@ -1691,8 +1733,8 @@ class WebDriver extends Helper {
|
|
|
1691
1733
|
*
|
|
1692
1734
|
*/
|
|
1693
1735
|
async seeCurrentUrlEquals(url) {
|
|
1694
|
-
const res = await this.browser.getUrl()
|
|
1695
|
-
return urlEquals(this.options.url).assert(url, decodeUrl(res))
|
|
1736
|
+
const res = await this.browser.getUrl()
|
|
1737
|
+
return urlEquals(this.options.url).assert(url, decodeUrl(res))
|
|
1696
1738
|
}
|
|
1697
1739
|
|
|
1698
1740
|
/**
|
|
@@ -1700,8 +1742,8 @@ class WebDriver extends Helper {
|
|
|
1700
1742
|
*
|
|
1701
1743
|
*/
|
|
1702
1744
|
async dontSeeCurrentUrlEquals(url) {
|
|
1703
|
-
const res = await this.browser.getUrl()
|
|
1704
|
-
return urlEquals(this.options.url).negate(url, decodeUrl(res))
|
|
1745
|
+
const res = await this.browser.getUrl()
|
|
1746
|
+
return urlEquals(this.options.url).negate(url, decodeUrl(res))
|
|
1705
1747
|
}
|
|
1706
1748
|
|
|
1707
1749
|
/**
|
|
@@ -1710,7 +1752,7 @@ class WebDriver extends Helper {
|
|
|
1710
1752
|
* {{> executeScript }}
|
|
1711
1753
|
*/
|
|
1712
1754
|
executeScript(...args) {
|
|
1713
|
-
return this.browser.execute.apply(this.browser, args)
|
|
1755
|
+
return this.browser.execute.apply(this.browser, args)
|
|
1714
1756
|
}
|
|
1715
1757
|
|
|
1716
1758
|
/**
|
|
@@ -1718,7 +1760,7 @@ class WebDriver extends Helper {
|
|
|
1718
1760
|
*
|
|
1719
1761
|
*/
|
|
1720
1762
|
executeAsyncScript(...args) {
|
|
1721
|
-
return this.browser.executeAsync.apply(this.browser, args)
|
|
1763
|
+
return this.browser.executeAsync.apply(this.browser, args)
|
|
1722
1764
|
}
|
|
1723
1765
|
|
|
1724
1766
|
/**
|
|
@@ -1726,10 +1768,10 @@ class WebDriver extends Helper {
|
|
|
1726
1768
|
*
|
|
1727
1769
|
*/
|
|
1728
1770
|
async scrollIntoView(locator, scrollIntoViewOptions) {
|
|
1729
|
-
const res = await this._locate(withStrictLocator(locator), true)
|
|
1730
|
-
assertElementExists(res, locator)
|
|
1731
|
-
const elem = usingFirstElement(res)
|
|
1732
|
-
return elem.scrollIntoView(scrollIntoViewOptions)
|
|
1771
|
+
const res = await this._locate(withStrictLocator(locator), true)
|
|
1772
|
+
assertElementExists(res, locator)
|
|
1773
|
+
const elem = usingFirstElement(res)
|
|
1774
|
+
return elem.scrollIntoView(scrollIntoViewOptions)
|
|
1733
1775
|
}
|
|
1734
1776
|
|
|
1735
1777
|
/**
|
|
@@ -1738,28 +1780,40 @@ class WebDriver extends Helper {
|
|
|
1738
1780
|
*/
|
|
1739
1781
|
async scrollTo(locator, offsetX = 0, offsetY = 0) {
|
|
1740
1782
|
if (typeof locator === 'number' && typeof offsetX === 'number') {
|
|
1741
|
-
offsetY = offsetX
|
|
1742
|
-
offsetX = locator
|
|
1743
|
-
locator = null
|
|
1783
|
+
offsetY = offsetX
|
|
1784
|
+
offsetX = locator
|
|
1785
|
+
locator = null
|
|
1744
1786
|
}
|
|
1745
1787
|
|
|
1746
1788
|
if (locator) {
|
|
1747
|
-
const res = await this._locate(withStrictLocator(locator), true)
|
|
1748
|
-
assertElementExists(res, locator)
|
|
1749
|
-
const elem = usingFirstElement(res)
|
|
1750
|
-
const elementId = getElementId(elem)
|
|
1751
|
-
if (this.browser.isMobile && !this.browser.isW3C) return this.browser.touchScroll(offsetX, offsetY, elementId)
|
|
1752
|
-
const location = await elem.getLocation()
|
|
1753
|
-
assertElementExists(location, locator, 'Failed to receive', 'location')
|
|
1789
|
+
const res = await this._locate(withStrictLocator(locator), true)
|
|
1790
|
+
assertElementExists(res, locator)
|
|
1791
|
+
const elem = usingFirstElement(res)
|
|
1792
|
+
const elementId = getElementId(elem)
|
|
1793
|
+
if (this.browser.isMobile && !this.browser.isW3C) return this.browser.touchScroll(offsetX, offsetY, elementId)
|
|
1794
|
+
const location = await elem.getLocation()
|
|
1795
|
+
assertElementExists(location, locator, 'Failed to receive', 'location')
|
|
1754
1796
|
/* eslint-disable prefer-arrow-callback */
|
|
1755
|
-
return this.browser.execute(
|
|
1797
|
+
return this.browser.execute(
|
|
1798
|
+
function (x, y) {
|
|
1799
|
+
return window.scrollTo(x, y)
|
|
1800
|
+
},
|
|
1801
|
+
location.x + offsetX,
|
|
1802
|
+
location.y + offsetY,
|
|
1803
|
+
)
|
|
1756
1804
|
/* eslint-enable */
|
|
1757
1805
|
}
|
|
1758
1806
|
|
|
1759
|
-
if (this.browser.isMobile && !this.browser.isW3C) return this.browser.touchScroll(locator, offsetX, offsetY)
|
|
1807
|
+
if (this.browser.isMobile && !this.browser.isW3C) return this.browser.touchScroll(locator, offsetX, offsetY)
|
|
1760
1808
|
|
|
1761
1809
|
/* eslint-disable prefer-arrow-callback, comma-dangle */
|
|
1762
|
-
return this.browser.execute(
|
|
1810
|
+
return this.browser.execute(
|
|
1811
|
+
function (x, y) {
|
|
1812
|
+
return window.scrollTo(x, y)
|
|
1813
|
+
},
|
|
1814
|
+
offsetX,
|
|
1815
|
+
offsetY,
|
|
1816
|
+
)
|
|
1763
1817
|
/* eslint-enable */
|
|
1764
1818
|
}
|
|
1765
1819
|
|
|
@@ -1767,13 +1821,13 @@ class WebDriver extends Helper {
|
|
|
1767
1821
|
* {{> moveCursorTo }}
|
|
1768
1822
|
*/
|
|
1769
1823
|
async moveCursorTo(locator, xOffset, yOffset) {
|
|
1770
|
-
const res = await this._locate(withStrictLocator(locator), true)
|
|
1771
|
-
assertElementExists(res, locator)
|
|
1772
|
-
const elem = usingFirstElement(res)
|
|
1824
|
+
const res = await this._locate(withStrictLocator(locator), true)
|
|
1825
|
+
assertElementExists(res, locator)
|
|
1826
|
+
const elem = usingFirstElement(res)
|
|
1773
1827
|
try {
|
|
1774
|
-
await elem.moveTo({ xOffset, yOffset })
|
|
1828
|
+
await elem.moveTo({ xOffset, yOffset })
|
|
1775
1829
|
} catch (e) {
|
|
1776
|
-
debug(e.message)
|
|
1830
|
+
debug(e.message)
|
|
1777
1831
|
}
|
|
1778
1832
|
}
|
|
1779
1833
|
|
|
@@ -1782,61 +1836,63 @@ class WebDriver extends Helper {
|
|
|
1782
1836
|
*
|
|
1783
1837
|
*/
|
|
1784
1838
|
async saveElementScreenshot(locator, fileName) {
|
|
1785
|
-
const outputFile = screenshotOutputFolder(fileName)
|
|
1839
|
+
const outputFile = screenshotOutputFolder(fileName)
|
|
1786
1840
|
|
|
1787
|
-
const res = await this._locate(withStrictLocator(locator), true)
|
|
1788
|
-
assertElementExists(res, locator)
|
|
1789
|
-
const elem = usingFirstElement(res)
|
|
1841
|
+
const res = await this._locate(withStrictLocator(locator), true)
|
|
1842
|
+
assertElementExists(res, locator)
|
|
1843
|
+
const elem = usingFirstElement(res)
|
|
1790
1844
|
|
|
1791
|
-
this.debug(`Screenshot of ${
|
|
1792
|
-
return elem.saveScreenshot(outputFile)
|
|
1845
|
+
this.debug(`Screenshot of ${new Locator(locator)} element has been saved to ${outputFile}`)
|
|
1846
|
+
return elem.saveScreenshot(outputFile)
|
|
1793
1847
|
}
|
|
1794
1848
|
|
|
1795
1849
|
/**
|
|
1796
1850
|
* {{> saveScreenshot }}
|
|
1797
1851
|
*/
|
|
1798
1852
|
async saveScreenshot(fileName, fullPage = false) {
|
|
1799
|
-
let outputFile = screenshotOutputFolder(fileName)
|
|
1853
|
+
let outputFile = screenshotOutputFolder(fileName)
|
|
1800
1854
|
|
|
1801
1855
|
if (this.activeSessionName) {
|
|
1802
|
-
const browser = this.sessionWindows[this.activeSessionName]
|
|
1856
|
+
const browser = this.sessionWindows[this.activeSessionName]
|
|
1803
1857
|
|
|
1804
1858
|
for (const sessionName in this.sessionWindows) {
|
|
1805
|
-
const activeSessionPage = this.sessionWindows[sessionName]
|
|
1806
|
-
outputFile = screenshotOutputFolder(`${sessionName}_${fileName}`)
|
|
1859
|
+
const activeSessionPage = this.sessionWindows[sessionName]
|
|
1860
|
+
outputFile = screenshotOutputFolder(`${sessionName}_${fileName}`)
|
|
1807
1861
|
|
|
1808
|
-
this.debug(`${sessionName} - Screenshot is saving to ${outputFile}`)
|
|
1862
|
+
this.debug(`${sessionName} - Screenshot is saving to ${outputFile}`)
|
|
1809
1863
|
|
|
1810
1864
|
if (browser) {
|
|
1811
|
-
this.debug(`Screenshot of ${sessionName} session has been saved to ${outputFile}`)
|
|
1812
|
-
return browser.saveScreenshot(outputFile)
|
|
1865
|
+
this.debug(`Screenshot of ${sessionName} session has been saved to ${outputFile}`)
|
|
1866
|
+
return browser.saveScreenshot(outputFile)
|
|
1813
1867
|
}
|
|
1814
1868
|
}
|
|
1815
1869
|
}
|
|
1816
1870
|
|
|
1817
1871
|
if (!fullPage) {
|
|
1818
|
-
this.debug(`Screenshot has been saved to ${outputFile}`)
|
|
1819
|
-
return this.browser.saveScreenshot(outputFile)
|
|
1872
|
+
this.debug(`Screenshot has been saved to ${outputFile}`)
|
|
1873
|
+
return this.browser.saveScreenshot(outputFile)
|
|
1820
1874
|
}
|
|
1821
1875
|
|
|
1822
1876
|
/* eslint-disable prefer-arrow-callback, comma-dangle, prefer-const */
|
|
1823
|
-
const originalWindowSize = await this.browser.getWindowSize()
|
|
1877
|
+
const originalWindowSize = await this.browser.getWindowSize()
|
|
1824
1878
|
|
|
1825
|
-
let { width, height } = await this.browser
|
|
1826
|
-
|
|
1827
|
-
|
|
1828
|
-
|
|
1829
|
-
|
|
1830
|
-
|
|
1879
|
+
let { width, height } = await this.browser
|
|
1880
|
+
.execute(function () {
|
|
1881
|
+
return {
|
|
1882
|
+
height: document.body.scrollHeight,
|
|
1883
|
+
width: document.body.scrollWidth,
|
|
1884
|
+
}
|
|
1885
|
+
})
|
|
1886
|
+
.then((res) => res)
|
|
1831
1887
|
|
|
1832
|
-
if (height < 100) height = 500
|
|
1888
|
+
if (height < 100) height = 500 // errors for very small height
|
|
1833
1889
|
/* eslint-enable */
|
|
1834
1890
|
|
|
1835
|
-
await this.browser.setWindowSize(width, height)
|
|
1836
|
-
this.debug(`Screenshot has been saved to ${outputFile}, size: ${width}x${height}`)
|
|
1837
|
-
const buffer = await this.browser.saveScreenshot(outputFile)
|
|
1838
|
-
await this.browser.setWindowSize(originalWindowSize.width, originalWindowSize.height)
|
|
1839
|
-
return buffer
|
|
1891
|
+
await this.browser.setWindowSize(width, height)
|
|
1892
|
+
this.debug(`Screenshot has been saved to ${outputFile}, size: ${width}x${height}`)
|
|
1893
|
+
const buffer = await this.browser.saveScreenshot(outputFile)
|
|
1894
|
+
await this.browser.setWindowSize(originalWindowSize.width, originalWindowSize.height)
|
|
1895
|
+
return buffer
|
|
1840
1896
|
}
|
|
1841
1897
|
|
|
1842
1898
|
/**
|
|
@@ -1844,40 +1900,40 @@ class WebDriver extends Helper {
|
|
|
1844
1900
|
* {{> setCookie }}
|
|
1845
1901
|
*/
|
|
1846
1902
|
async setCookie(cookie) {
|
|
1847
|
-
return this.browser.setCookies(cookie)
|
|
1903
|
+
return this.browser.setCookies(cookie)
|
|
1848
1904
|
}
|
|
1849
1905
|
|
|
1850
1906
|
/**
|
|
1851
1907
|
* {{> clearCookie }}
|
|
1852
1908
|
*/
|
|
1853
1909
|
async clearCookie(cookie) {
|
|
1854
|
-
return this.browser.deleteCookies(cookie)
|
|
1910
|
+
return this.browser.deleteCookies(cookie)
|
|
1855
1911
|
}
|
|
1856
1912
|
|
|
1857
1913
|
/**
|
|
1858
1914
|
* {{> seeCookie }}
|
|
1859
1915
|
*/
|
|
1860
1916
|
async seeCookie(name) {
|
|
1861
|
-
const cookie = await this.browser.getCookies([name])
|
|
1862
|
-
return truth(`cookie ${name}`, 'to be set').assert(cookie)
|
|
1917
|
+
const cookie = await this.browser.getCookies([name])
|
|
1918
|
+
return truth(`cookie ${name}`, 'to be set').assert(cookie)
|
|
1863
1919
|
}
|
|
1864
1920
|
|
|
1865
1921
|
/**
|
|
1866
1922
|
* {{> dontSeeCookie }}
|
|
1867
1923
|
*/
|
|
1868
1924
|
async dontSeeCookie(name) {
|
|
1869
|
-
const cookie = await this.browser.getCookies([name])
|
|
1870
|
-
return truth(`cookie ${name}`, 'to be set').negate(cookie)
|
|
1925
|
+
const cookie = await this.browser.getCookies([name])
|
|
1926
|
+
return truth(`cookie ${name}`, 'to be set').negate(cookie)
|
|
1871
1927
|
}
|
|
1872
1928
|
|
|
1873
1929
|
/**
|
|
1874
1930
|
* {{> grabCookie }}
|
|
1875
1931
|
*/
|
|
1876
1932
|
async grabCookie(name) {
|
|
1877
|
-
if (!name) return this.browser.getCookies()
|
|
1878
|
-
const cookie = await this.browser.getCookies([name])
|
|
1879
|
-
this.debugSection('Cookie', JSON.stringify(cookie))
|
|
1880
|
-
return cookie[0]
|
|
1933
|
+
if (!name) return this.browser.getCookies()
|
|
1934
|
+
const cookie = await this.browser.getCookies([name])
|
|
1935
|
+
this.debugSection('Cookie', JSON.stringify(cookie))
|
|
1936
|
+
return cookie[0]
|
|
1881
1937
|
}
|
|
1882
1938
|
|
|
1883
1939
|
/**
|
|
@@ -1885,30 +1941,33 @@ class WebDriver extends Helper {
|
|
|
1885
1941
|
*/
|
|
1886
1942
|
async waitForCookie(name, sec) {
|
|
1887
1943
|
// by default, we will retry 3 times
|
|
1888
|
-
let retries = 3
|
|
1889
|
-
const waitTimeout = sec || this.options.waitForTimeoutInSeconds
|
|
1944
|
+
let retries = 3
|
|
1945
|
+
const waitTimeout = sec || this.options.waitForTimeoutInSeconds
|
|
1890
1946
|
|
|
1891
1947
|
if (sec) {
|
|
1892
|
-
retries = sec
|
|
1948
|
+
retries = sec
|
|
1893
1949
|
} else {
|
|
1894
|
-
retries = waitTimeout - 1
|
|
1950
|
+
retries = waitTimeout - 1
|
|
1895
1951
|
}
|
|
1896
1952
|
|
|
1897
|
-
return promiseRetry(
|
|
1898
|
-
|
|
1899
|
-
const
|
|
1900
|
-
|
|
1901
|
-
|
|
1953
|
+
return promiseRetry(
|
|
1954
|
+
async (retry, number) => {
|
|
1955
|
+
const _grabCookie = async (name) => {
|
|
1956
|
+
const cookie = await this.browser.getCookies([name])
|
|
1957
|
+
if (cookie.length === 0) throw Error(`Cookie ${name} is not found after ${retries}s`)
|
|
1958
|
+
}
|
|
1902
1959
|
|
|
1903
|
-
|
|
1904
|
-
|
|
1960
|
+
this.debugSection('Wait for cookie: ', name)
|
|
1961
|
+
if (number > 1) this.debugSection('Retrying... Attempt #', number)
|
|
1905
1962
|
|
|
1906
|
-
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1963
|
+
try {
|
|
1964
|
+
await _grabCookie(name)
|
|
1965
|
+
} catch (e) {
|
|
1966
|
+
retry(e)
|
|
1967
|
+
}
|
|
1968
|
+
},
|
|
1969
|
+
{ retries, maxTimeout: 1000 },
|
|
1970
|
+
)
|
|
1912
1971
|
}
|
|
1913
1972
|
|
|
1914
1973
|
/**
|
|
@@ -1919,9 +1978,9 @@ class WebDriver extends Helper {
|
|
|
1919
1978
|
async acceptPopup() {
|
|
1920
1979
|
return this.browser.getAlertText().then((res) => {
|
|
1921
1980
|
if (res !== null) {
|
|
1922
|
-
return this.browser.acceptAlert()
|
|
1981
|
+
return this.browser.acceptAlert()
|
|
1923
1982
|
}
|
|
1924
|
-
})
|
|
1983
|
+
})
|
|
1925
1984
|
}
|
|
1926
1985
|
|
|
1927
1986
|
/**
|
|
@@ -1931,9 +1990,9 @@ class WebDriver extends Helper {
|
|
|
1931
1990
|
async cancelPopup() {
|
|
1932
1991
|
return this.browser.getAlertText().then((res) => {
|
|
1933
1992
|
if (res !== null) {
|
|
1934
|
-
return this.browser.dismissAlert()
|
|
1993
|
+
return this.browser.dismissAlert()
|
|
1935
1994
|
}
|
|
1936
|
-
})
|
|
1995
|
+
})
|
|
1937
1996
|
}
|
|
1938
1997
|
|
|
1939
1998
|
/**
|
|
@@ -1945,10 +2004,10 @@ class WebDriver extends Helper {
|
|
|
1945
2004
|
async seeInPopup(text) {
|
|
1946
2005
|
return this.browser.getAlertText().then((res) => {
|
|
1947
2006
|
if (res === null) {
|
|
1948
|
-
throw new Error('Popup is not opened')
|
|
2007
|
+
throw new Error('Popup is not opened')
|
|
1949
2008
|
}
|
|
1950
|
-
stringIncludes('text in popup').assert(text, res)
|
|
1951
|
-
})
|
|
2009
|
+
stringIncludes('text in popup').assert(text, res)
|
|
2010
|
+
})
|
|
1952
2011
|
}
|
|
1953
2012
|
|
|
1954
2013
|
/**
|
|
@@ -1956,9 +2015,9 @@ class WebDriver extends Helper {
|
|
|
1956
2015
|
*/
|
|
1957
2016
|
async grabPopupText() {
|
|
1958
2017
|
try {
|
|
1959
|
-
return await this.browser.getAlertText()
|
|
2018
|
+
return await this.browser.getAlertText()
|
|
1960
2019
|
} catch (err) {
|
|
1961
|
-
this.debugSection('Popup', 'Error getting text from popup')
|
|
2020
|
+
this.debugSection('Popup', 'Error getting text from popup')
|
|
1962
2021
|
}
|
|
1963
2022
|
}
|
|
1964
2023
|
|
|
@@ -1966,36 +2025,44 @@ class WebDriver extends Helper {
|
|
|
1966
2025
|
* {{> pressKeyDown }}
|
|
1967
2026
|
*/
|
|
1968
2027
|
async pressKeyDown(key) {
|
|
1969
|
-
key = getNormalizedKey.call(this, key)
|
|
2028
|
+
key = getNormalizedKey.call(this, key)
|
|
1970
2029
|
if (!this.browser.isW3C) {
|
|
1971
|
-
return this.browser.sendKeys([key])
|
|
2030
|
+
return this.browser.sendKeys([key])
|
|
1972
2031
|
}
|
|
1973
|
-
return this.browser.performActions([
|
|
1974
|
-
|
|
1975
|
-
|
|
1976
|
-
|
|
1977
|
-
|
|
1978
|
-
|
|
1979
|
-
|
|
1980
|
-
|
|
2032
|
+
return this.browser.performActions([
|
|
2033
|
+
{
|
|
2034
|
+
type: 'key',
|
|
2035
|
+
id: 'keyboard',
|
|
2036
|
+
actions: [
|
|
2037
|
+
{
|
|
2038
|
+
type: 'keyDown',
|
|
2039
|
+
value: key,
|
|
2040
|
+
},
|
|
2041
|
+
],
|
|
2042
|
+
},
|
|
2043
|
+
])
|
|
1981
2044
|
}
|
|
1982
2045
|
|
|
1983
2046
|
/**
|
|
1984
2047
|
* {{> pressKeyUp }}
|
|
1985
2048
|
*/
|
|
1986
2049
|
async pressKeyUp(key) {
|
|
1987
|
-
key = getNormalizedKey.call(this, key)
|
|
2050
|
+
key = getNormalizedKey.call(this, key)
|
|
1988
2051
|
if (!this.browser.isW3C) {
|
|
1989
|
-
return this.browser.sendKeys([key])
|
|
2052
|
+
return this.browser.sendKeys([key])
|
|
1990
2053
|
}
|
|
1991
|
-
return this.browser.performActions([
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
|
|
2054
|
+
return this.browser.performActions([
|
|
2055
|
+
{
|
|
2056
|
+
type: 'key',
|
|
2057
|
+
id: 'keyboard',
|
|
2058
|
+
actions: [
|
|
2059
|
+
{
|
|
2060
|
+
type: 'keyUp',
|
|
2061
|
+
value: key,
|
|
2062
|
+
},
|
|
2063
|
+
],
|
|
2064
|
+
},
|
|
2065
|
+
])
|
|
1999
2066
|
}
|
|
2000
2067
|
|
|
2001
2068
|
/**
|
|
@@ -2004,40 +2071,45 @@ class WebDriver extends Helper {
|
|
|
2004
2071
|
* {{> pressKeyWithKeyNormalization }}
|
|
2005
2072
|
*/
|
|
2006
2073
|
async pressKey(key) {
|
|
2007
|
-
const modifiers = []
|
|
2074
|
+
const modifiers = []
|
|
2008
2075
|
if (Array.isArray(key)) {
|
|
2009
2076
|
for (let k of key) {
|
|
2010
|
-
k = getNormalizedKey.call(this, k)
|
|
2077
|
+
k = getNormalizedKey.call(this, k)
|
|
2011
2078
|
if (isModifierKey(k)) {
|
|
2012
|
-
modifiers.push(k)
|
|
2079
|
+
modifiers.push(k)
|
|
2013
2080
|
} else {
|
|
2014
|
-
key = k
|
|
2015
|
-
break
|
|
2081
|
+
key = k
|
|
2082
|
+
break
|
|
2016
2083
|
}
|
|
2017
2084
|
}
|
|
2018
2085
|
} else {
|
|
2019
|
-
key = getNormalizedKey.call(this, key)
|
|
2086
|
+
key = getNormalizedKey.call(this, key)
|
|
2020
2087
|
}
|
|
2021
2088
|
for (const modifier of modifiers) {
|
|
2022
|
-
await this.pressKeyDown(modifier)
|
|
2089
|
+
await this.pressKeyDown(modifier)
|
|
2023
2090
|
}
|
|
2024
2091
|
if (!this.browser.isW3C) {
|
|
2025
|
-
await this.browser.sendKeys([key])
|
|
2092
|
+
await this.browser.sendKeys([key])
|
|
2026
2093
|
} else {
|
|
2027
|
-
await this.browser.performActions([
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2094
|
+
await this.browser.performActions([
|
|
2095
|
+
{
|
|
2096
|
+
type: 'key',
|
|
2097
|
+
id: 'keyboard',
|
|
2098
|
+
actions: [
|
|
2099
|
+
{
|
|
2100
|
+
type: 'keyDown',
|
|
2101
|
+
value: key,
|
|
2102
|
+
},
|
|
2103
|
+
{
|
|
2104
|
+
type: 'keyUp',
|
|
2105
|
+
value: key,
|
|
2106
|
+
},
|
|
2107
|
+
],
|
|
2108
|
+
},
|
|
2109
|
+
])
|
|
2038
2110
|
}
|
|
2039
2111
|
for (const modifier of modifiers) {
|
|
2040
|
-
await this.pressKeyUp(modifier)
|
|
2112
|
+
await this.pressKeyUp(modifier)
|
|
2041
2113
|
}
|
|
2042
2114
|
}
|
|
2043
2115
|
|
|
@@ -2046,17 +2118,17 @@ class WebDriver extends Helper {
|
|
|
2046
2118
|
*/
|
|
2047
2119
|
async type(keys, delay = null) {
|
|
2048
2120
|
if (!Array.isArray(keys)) {
|
|
2049
|
-
keys = keys.toString()
|
|
2050
|
-
keys = keys.split('')
|
|
2121
|
+
keys = keys.toString()
|
|
2122
|
+
keys = keys.split('')
|
|
2051
2123
|
}
|
|
2052
2124
|
if (delay) {
|
|
2053
2125
|
for (const key of keys) {
|
|
2054
|
-
await this.browser.keys(key)
|
|
2055
|
-
await this.wait(delay / 1000)
|
|
2126
|
+
await this.browser.keys(key)
|
|
2127
|
+
await this.wait(delay / 1000)
|
|
2056
2128
|
}
|
|
2057
|
-
return
|
|
2129
|
+
return
|
|
2058
2130
|
}
|
|
2059
|
-
await this.browser.keys(keys)
|
|
2131
|
+
await this.browser.keys(keys)
|
|
2060
2132
|
}
|
|
2061
2133
|
|
|
2062
2134
|
/**
|
|
@@ -2065,27 +2137,27 @@ class WebDriver extends Helper {
|
|
|
2065
2137
|
* {{> resizeWindow }}
|
|
2066
2138
|
*/
|
|
2067
2139
|
async resizeWindow(width, height) {
|
|
2068
|
-
return this.browser.setWindowSize(width, height)
|
|
2140
|
+
return this.browser.setWindowSize(width, height)
|
|
2069
2141
|
}
|
|
2070
2142
|
|
|
2071
2143
|
async _resizeBrowserWindow(browser, width, height) {
|
|
2072
2144
|
if (width === 'maximize') {
|
|
2073
|
-
const size = await browser.maximizeWindow()
|
|
2074
|
-
this.debugSection('Window Size', size)
|
|
2075
|
-
return
|
|
2145
|
+
const size = await browser.maximizeWindow()
|
|
2146
|
+
this.debugSection('Window Size', size)
|
|
2147
|
+
return
|
|
2076
2148
|
}
|
|
2077
2149
|
if (browser.isW3C) {
|
|
2078
|
-
return browser.setWindowRect(null, null, parseInt(width, 10), parseInt(height, 10))
|
|
2150
|
+
return browser.setWindowRect(null, null, parseInt(width, 10), parseInt(height, 10))
|
|
2079
2151
|
}
|
|
2080
|
-
return browser.setWindowSize(parseInt(width, 10), parseInt(height, 10))
|
|
2152
|
+
return browser.setWindowSize(parseInt(width, 10), parseInt(height, 10))
|
|
2081
2153
|
}
|
|
2082
2154
|
|
|
2083
2155
|
async _resizeWindowIfNeeded(browser, windowSize) {
|
|
2084
2156
|
if (this.isWeb && windowSize === 'maximize') {
|
|
2085
|
-
await this._resizeBrowserWindow(browser, 'maximize')
|
|
2157
|
+
await this._resizeBrowserWindow(browser, 'maximize')
|
|
2086
2158
|
} else if (this.isWeb && windowSize && windowSize.indexOf('x') > 0) {
|
|
2087
|
-
const dimensions = windowSize.split('x')
|
|
2088
|
-
await this._resizeBrowserWindow(browser, dimensions[0], dimensions[1])
|
|
2159
|
+
const dimensions = windowSize.split('x')
|
|
2160
|
+
await this._resizeBrowserWindow(browser, dimensions[0], dimensions[1])
|
|
2089
2161
|
}
|
|
2090
2162
|
}
|
|
2091
2163
|
|
|
@@ -2094,11 +2166,11 @@ class WebDriver extends Helper {
|
|
|
2094
2166
|
*
|
|
2095
2167
|
*/
|
|
2096
2168
|
async focus(locator) {
|
|
2097
|
-
const els = await this._locate(locator)
|
|
2098
|
-
assertElementExists(els, locator, 'Element to focus')
|
|
2099
|
-
const el = usingFirstElement(els)
|
|
2169
|
+
const els = await this._locate(locator)
|
|
2170
|
+
assertElementExists(els, locator, 'Element to focus')
|
|
2171
|
+
const el = usingFirstElement(els)
|
|
2100
2172
|
|
|
2101
|
-
await focusElement(el, this.browser)
|
|
2173
|
+
await focusElement(el, this.browser)
|
|
2102
2174
|
}
|
|
2103
2175
|
|
|
2104
2176
|
/**
|
|
@@ -2106,11 +2178,11 @@ class WebDriver extends Helper {
|
|
|
2106
2178
|
*
|
|
2107
2179
|
*/
|
|
2108
2180
|
async blur(locator) {
|
|
2109
|
-
const els = await this._locate(locator)
|
|
2110
|
-
assertElementExists(els, locator, 'Element to blur')
|
|
2111
|
-
const el = usingFirstElement(els)
|
|
2181
|
+
const els = await this._locate(locator)
|
|
2182
|
+
assertElementExists(els, locator, 'Element to blur')
|
|
2183
|
+
const el = usingFirstElement(els)
|
|
2112
2184
|
|
|
2113
|
-
await blurElement(el, this.browser)
|
|
2185
|
+
await blurElement(el, this.browser)
|
|
2114
2186
|
}
|
|
2115
2187
|
|
|
2116
2188
|
/**
|
|
@@ -2118,64 +2190,73 @@ class WebDriver extends Helper {
|
|
|
2118
2190
|
* {{> dragAndDrop }}
|
|
2119
2191
|
*/
|
|
2120
2192
|
async dragAndDrop(srcElement, destElement) {
|
|
2121
|
-
let sourceEl = await this._locate(srcElement)
|
|
2122
|
-
assertElementExists(sourceEl, srcElement)
|
|
2123
|
-
sourceEl = usingFirstElement(sourceEl)
|
|
2193
|
+
let sourceEl = await this._locate(srcElement)
|
|
2194
|
+
assertElementExists(sourceEl, srcElement)
|
|
2195
|
+
sourceEl = usingFirstElement(sourceEl)
|
|
2124
2196
|
|
|
2125
|
-
let destEl = await this._locate(destElement)
|
|
2126
|
-
assertElementExists(destEl, destElement)
|
|
2127
|
-
destEl = usingFirstElement(destEl)
|
|
2197
|
+
let destEl = await this._locate(destElement)
|
|
2198
|
+
assertElementExists(destEl, destElement)
|
|
2199
|
+
destEl = usingFirstElement(destEl)
|
|
2128
2200
|
|
|
2129
|
-
return sourceEl.dragAndDrop(destEl)
|
|
2201
|
+
return sourceEl.dragAndDrop(destEl)
|
|
2130
2202
|
}
|
|
2131
2203
|
|
|
2132
2204
|
/**
|
|
2133
2205
|
* {{> dragSlider }}
|
|
2134
2206
|
*/
|
|
2135
2207
|
async dragSlider(locator, offsetX = 0) {
|
|
2136
|
-
const browser = this.browser
|
|
2137
|
-
await this.moveCursorTo(locator)
|
|
2208
|
+
const browser = this.browser
|
|
2209
|
+
await this.moveCursorTo(locator)
|
|
2138
2210
|
|
|
2139
2211
|
// for chrome
|
|
2140
2212
|
if (browser.isW3C) {
|
|
2141
|
-
const xOffset = await this.grabElementBoundingRect(locator, 'x')
|
|
2142
|
-
const yOffset = await this.grabElementBoundingRect(locator, 'y')
|
|
2143
|
-
|
|
2144
|
-
return browser.performActions([
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2160
|
-
|
|
2161
|
-
|
|
2162
|
-
|
|
2163
|
-
|
|
2164
|
-
|
|
2213
|
+
const xOffset = await this.grabElementBoundingRect(locator, 'x')
|
|
2214
|
+
const yOffset = await this.grabElementBoundingRect(locator, 'y')
|
|
2215
|
+
|
|
2216
|
+
return browser.performActions([
|
|
2217
|
+
{
|
|
2218
|
+
type: 'pointer',
|
|
2219
|
+
id: 'pointer1',
|
|
2220
|
+
parameters: { pointerType: 'mouse' },
|
|
2221
|
+
actions: [
|
|
2222
|
+
{
|
|
2223
|
+
type: 'pointerMove',
|
|
2224
|
+
origin: 'pointer',
|
|
2225
|
+
duration: 1000,
|
|
2226
|
+
x: xOffset,
|
|
2227
|
+
y: yOffset,
|
|
2228
|
+
},
|
|
2229
|
+
{ type: 'pointerDown', button: 0 },
|
|
2230
|
+
{
|
|
2231
|
+
type: 'pointerMove',
|
|
2232
|
+
origin: 'pointer',
|
|
2233
|
+
duration: 1000,
|
|
2234
|
+
x: offsetX,
|
|
2235
|
+
y: 0,
|
|
2236
|
+
},
|
|
2237
|
+
{ type: 'pointerUp', button: 0 },
|
|
2238
|
+
],
|
|
2239
|
+
},
|
|
2240
|
+
])
|
|
2241
|
+
}
|
|
2242
|
+
|
|
2243
|
+
await browser.buttonDown(0)
|
|
2244
|
+
await browser.moveToElement(null, offsetX, 0)
|
|
2245
|
+
await browser.buttonUp(0)
|
|
2165
2246
|
}
|
|
2166
2247
|
|
|
2167
2248
|
/**
|
|
2168
2249
|
* {{> grabAllWindowHandles }}
|
|
2169
2250
|
*/
|
|
2170
2251
|
async grabAllWindowHandles() {
|
|
2171
|
-
return this.browser.getWindowHandles()
|
|
2252
|
+
return this.browser.getWindowHandles()
|
|
2172
2253
|
}
|
|
2173
2254
|
|
|
2174
2255
|
/**
|
|
2175
2256
|
* {{> grabCurrentWindowHandle }}
|
|
2176
2257
|
*/
|
|
2177
2258
|
async grabCurrentWindowHandle() {
|
|
2178
|
-
return this.browser.getWindowHandle()
|
|
2259
|
+
return this.browser.getWindowHandle()
|
|
2179
2260
|
}
|
|
2180
2261
|
|
|
2181
2262
|
/**
|
|
@@ -2193,125 +2274,140 @@ class WebDriver extends Helper {
|
|
|
2193
2274
|
* @param {string} window name of window handle.
|
|
2194
2275
|
*/
|
|
2195
2276
|
async switchToWindow(window) {
|
|
2196
|
-
await this.browser.switchToWindow(window)
|
|
2277
|
+
await this.browser.switchToWindow(window)
|
|
2197
2278
|
}
|
|
2198
2279
|
|
|
2199
2280
|
/**
|
|
2200
2281
|
* {{> closeOtherTabs }}
|
|
2201
2282
|
*/
|
|
2202
2283
|
async closeOtherTabs() {
|
|
2203
|
-
const handles = await this.browser.getWindowHandles()
|
|
2204
|
-
const currentHandle = await this.browser.getWindowHandle()
|
|
2205
|
-
const otherHandles = handles.filter(handle => handle !== currentHandle)
|
|
2284
|
+
const handles = await this.browser.getWindowHandles()
|
|
2285
|
+
const currentHandle = await this.browser.getWindowHandle()
|
|
2286
|
+
const otherHandles = handles.filter((handle) => handle !== currentHandle)
|
|
2206
2287
|
|
|
2207
2288
|
await forEachAsync(otherHandles, async (handle) => {
|
|
2208
|
-
await this.browser.switchToWindow(handle)
|
|
2209
|
-
await this.browser.closeWindow()
|
|
2210
|
-
})
|
|
2211
|
-
await this.browser.switchToWindow(currentHandle)
|
|
2289
|
+
await this.browser.switchToWindow(handle)
|
|
2290
|
+
await this.browser.closeWindow()
|
|
2291
|
+
})
|
|
2292
|
+
await this.browser.switchToWindow(currentHandle)
|
|
2212
2293
|
}
|
|
2213
2294
|
|
|
2214
2295
|
/**
|
|
2215
2296
|
* {{> wait }}
|
|
2216
2297
|
*/
|
|
2217
2298
|
async wait(sec) {
|
|
2218
|
-
return new Promise(resolve => {
|
|
2219
|
-
setTimeout(resolve, sec * 1000)
|
|
2220
|
-
})
|
|
2299
|
+
return new Promise((resolve) => {
|
|
2300
|
+
setTimeout(resolve, sec * 1000)
|
|
2301
|
+
})
|
|
2221
2302
|
}
|
|
2222
2303
|
|
|
2223
2304
|
/**
|
|
2224
2305
|
* {{> waitForEnabled }}
|
|
2225
2306
|
*/
|
|
2226
2307
|
async waitForEnabled(locator, sec = null) {
|
|
2227
|
-
const aSec = sec || this.options.waitForTimeoutInSeconds
|
|
2308
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds
|
|
2228
2309
|
|
|
2229
|
-
return this.browser.waitUntil(
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2234
|
-
|
|
2235
|
-
|
|
2236
|
-
|
|
2237
|
-
|
|
2238
|
-
|
|
2239
|
-
|
|
2240
|
-
|
|
2241
|
-
|
|
2242
|
-
|
|
2310
|
+
return this.browser.waitUntil(
|
|
2311
|
+
async () => {
|
|
2312
|
+
const res = await this._res(locator)
|
|
2313
|
+
if (!res || res.length === 0) {
|
|
2314
|
+
return false
|
|
2315
|
+
}
|
|
2316
|
+
const selected = await forEachAsync(res, async (el) => this.browser.isElementEnabled(getElementId(el)))
|
|
2317
|
+
if (Array.isArray(selected)) {
|
|
2318
|
+
return selected.filter((val) => val === true).length > 0
|
|
2319
|
+
}
|
|
2320
|
+
return selected
|
|
2321
|
+
},
|
|
2322
|
+
{
|
|
2323
|
+
timeout: aSec * 1000,
|
|
2324
|
+
timeoutMsg: `element (${new Locator(locator)}) still not enabled after ${aSec} sec`,
|
|
2325
|
+
},
|
|
2326
|
+
)
|
|
2243
2327
|
}
|
|
2244
2328
|
|
|
2245
2329
|
/**
|
|
2246
2330
|
* {{> waitForElement }}
|
|
2247
2331
|
*/
|
|
2248
2332
|
async waitForElement(locator, sec = null) {
|
|
2249
|
-
const aSec = sec || this.options.waitForTimeoutInSeconds
|
|
2333
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds
|
|
2250
2334
|
|
|
2251
|
-
return this.browser.waitUntil(
|
|
2252
|
-
|
|
2253
|
-
|
|
2254
|
-
|
|
2335
|
+
return this.browser.waitUntil(
|
|
2336
|
+
async () => {
|
|
2337
|
+
const res = await this._res(locator)
|
|
2338
|
+
return res && res.length
|
|
2339
|
+
},
|
|
2340
|
+
{
|
|
2341
|
+
timeout: aSec * 1000,
|
|
2342
|
+
timeoutMsg: `element (${new Locator(locator)}) still not present on page after ${aSec} sec`,
|
|
2343
|
+
},
|
|
2344
|
+
)
|
|
2255
2345
|
}
|
|
2256
2346
|
|
|
2257
2347
|
/**
|
|
2258
2348
|
* {{> waitForClickable }}
|
|
2259
2349
|
*/
|
|
2260
2350
|
async waitForClickable(locator, waitTimeout) {
|
|
2261
|
-
waitTimeout = waitTimeout || this.options.waitForTimeoutInSeconds
|
|
2262
|
-
let res = await this._locate(locator)
|
|
2263
|
-
res = usingFirstElement(res)
|
|
2264
|
-
assertElementExists(res, locator)
|
|
2351
|
+
waitTimeout = waitTimeout || this.options.waitForTimeoutInSeconds
|
|
2352
|
+
let res = await this._locate(locator)
|
|
2353
|
+
res = usingFirstElement(res)
|
|
2354
|
+
assertElementExists(res, locator)
|
|
2265
2355
|
|
|
2266
2356
|
return res.waitForClickable({
|
|
2267
2357
|
timeout: waitTimeout * 1000,
|
|
2268
2358
|
timeoutMsg: `element ${res.selector} still not clickable after ${waitTimeout} sec`,
|
|
2269
|
-
})
|
|
2359
|
+
})
|
|
2270
2360
|
}
|
|
2271
2361
|
|
|
2272
2362
|
/**
|
|
2273
2363
|
* {{> waitInUrl }}
|
|
2274
2364
|
*/
|
|
2275
2365
|
async waitInUrl(urlPart, sec = null) {
|
|
2276
|
-
const client = this.browser
|
|
2277
|
-
const aSec = sec || this.options.waitForTimeoutInSeconds
|
|
2278
|
-
let currUrl = ''
|
|
2366
|
+
const client = this.browser
|
|
2367
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds
|
|
2368
|
+
let currUrl = ''
|
|
2279
2369
|
|
|
2280
2370
|
return client
|
|
2281
|
-
.waitUntil(
|
|
2282
|
-
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2286
|
-
|
|
2371
|
+
.waitUntil(
|
|
2372
|
+
function () {
|
|
2373
|
+
return this.getUrl().then((res) => {
|
|
2374
|
+
currUrl = decodeUrl(res)
|
|
2375
|
+
return currUrl.indexOf(urlPart) > -1
|
|
2376
|
+
})
|
|
2377
|
+
},
|
|
2378
|
+
{ timeout: aSec * 1000 },
|
|
2379
|
+
)
|
|
2380
|
+
.catch((e) => {
|
|
2287
2381
|
if (e.message.indexOf('timeout')) {
|
|
2288
|
-
throw new Error(`expected url to include ${urlPart}, but found ${currUrl}`)
|
|
2382
|
+
throw new Error(`expected url to include ${urlPart}, but found ${currUrl}`)
|
|
2289
2383
|
}
|
|
2290
|
-
throw e
|
|
2291
|
-
})
|
|
2384
|
+
throw e
|
|
2385
|
+
})
|
|
2292
2386
|
}
|
|
2293
2387
|
|
|
2294
2388
|
/**
|
|
2295
2389
|
* {{> waitUrlEquals }}
|
|
2296
2390
|
*/
|
|
2297
2391
|
async waitUrlEquals(urlPart, sec = null) {
|
|
2298
|
-
const aSec = sec || this.options.waitForTimeoutInSeconds
|
|
2299
|
-
const baseUrl = this.options.url
|
|
2392
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds
|
|
2393
|
+
const baseUrl = this.options.url
|
|
2300
2394
|
if (urlPart.indexOf('http') < 0) {
|
|
2301
|
-
urlPart = baseUrl + urlPart
|
|
2302
|
-
}
|
|
2303
|
-
let currUrl = ''
|
|
2304
|
-
return this.browser
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
|
|
2310
|
-
|
|
2311
|
-
|
|
2312
|
-
|
|
2313
|
-
|
|
2314
|
-
|
|
2395
|
+
urlPart = baseUrl + urlPart
|
|
2396
|
+
}
|
|
2397
|
+
let currUrl = ''
|
|
2398
|
+
return this.browser
|
|
2399
|
+
.waitUntil(function () {
|
|
2400
|
+
return this.getUrl().then((res) => {
|
|
2401
|
+
currUrl = decodeUrl(res)
|
|
2402
|
+
return currUrl === urlPart
|
|
2403
|
+
})
|
|
2404
|
+
}, aSec * 1000)
|
|
2405
|
+
.catch((e) => {
|
|
2406
|
+
if (e.message.indexOf('timeout')) {
|
|
2407
|
+
throw new Error(`expected url to be ${urlPart}, but found ${currUrl}`)
|
|
2408
|
+
}
|
|
2409
|
+
throw e
|
|
2410
|
+
})
|
|
2315
2411
|
}
|
|
2316
2412
|
|
|
2317
2413
|
/**
|
|
@@ -2319,42 +2415,48 @@ class WebDriver extends Helper {
|
|
|
2319
2415
|
*
|
|
2320
2416
|
*/
|
|
2321
2417
|
async waitForText(text, sec = null, context = null) {
|
|
2322
|
-
const aSec = sec || this.options.waitForTimeoutInSeconds
|
|
2323
|
-
const _context = context || this.root
|
|
2324
|
-
|
|
2325
|
-
return this.browser.waitUntil(
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2329
|
-
|
|
2330
|
-
|
|
2331
|
-
|
|
2332
|
-
|
|
2333
|
-
|
|
2334
|
-
|
|
2335
|
-
|
|
2336
|
-
|
|
2418
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds
|
|
2419
|
+
const _context = context || this.root
|
|
2420
|
+
|
|
2421
|
+
return this.browser.waitUntil(
|
|
2422
|
+
async () => {
|
|
2423
|
+
const res = await this.$$(withStrictLocator.call(this, _context))
|
|
2424
|
+
if (!res || res.length === 0) return false
|
|
2425
|
+
const selected = await forEachAsync(res, async (el) => this.browser.getElementText(getElementId(el)))
|
|
2426
|
+
if (Array.isArray(selected)) {
|
|
2427
|
+
return selected.filter((part) => part.indexOf(text) >= 0).length > 0
|
|
2428
|
+
}
|
|
2429
|
+
return selected.indexOf(text) >= 0
|
|
2430
|
+
},
|
|
2431
|
+
{
|
|
2432
|
+
timeout: aSec * 1000,
|
|
2433
|
+
timeoutMsg: `element (${_context}) is not in DOM or there is no element(${_context}) with text "${text}" after ${aSec} sec`,
|
|
2434
|
+
},
|
|
2435
|
+
)
|
|
2337
2436
|
}
|
|
2338
2437
|
|
|
2339
2438
|
/**
|
|
2340
2439
|
* {{> waitForValue }}
|
|
2341
2440
|
*/
|
|
2342
2441
|
async waitForValue(field, value, sec = null) {
|
|
2343
|
-
const client = this.browser
|
|
2344
|
-
const aSec = sec || this.options.waitForTimeoutInSeconds
|
|
2345
|
-
|
|
2346
|
-
return client.waitUntil(
|
|
2347
|
-
|
|
2348
|
-
|
|
2349
|
-
|
|
2350
|
-
|
|
2351
|
-
|
|
2352
|
-
|
|
2353
|
-
|
|
2354
|
-
|
|
2355
|
-
|
|
2356
|
-
|
|
2357
|
-
|
|
2442
|
+
const client = this.browser
|
|
2443
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds
|
|
2444
|
+
|
|
2445
|
+
return client.waitUntil(
|
|
2446
|
+
async () => {
|
|
2447
|
+
const res = await findFields.call(this, field)
|
|
2448
|
+
if (!res || res.length === 0) return false
|
|
2449
|
+
const selected = await forEachAsync(res, async (el) => el.getValue())
|
|
2450
|
+
if (Array.isArray(selected)) {
|
|
2451
|
+
return selected.filter((part) => part.indexOf(value) >= 0).length > 0
|
|
2452
|
+
}
|
|
2453
|
+
return selected.indexOf(value) >= 0
|
|
2454
|
+
},
|
|
2455
|
+
{
|
|
2456
|
+
timeout: aSec * 1000,
|
|
2457
|
+
timeoutMsg: `element (${field}) is not in DOM or there is no element(${field}) with value "${value}" after ${aSec} sec`,
|
|
2458
|
+
},
|
|
2459
|
+
)
|
|
2358
2460
|
}
|
|
2359
2461
|
|
|
2360
2462
|
/**
|
|
@@ -2362,214 +2464,241 @@ class WebDriver extends Helper {
|
|
|
2362
2464
|
*
|
|
2363
2465
|
*/
|
|
2364
2466
|
async waitForVisible(locator, sec = null) {
|
|
2365
|
-
const aSec = sec || this.options.waitForTimeoutInSeconds
|
|
2366
|
-
|
|
2367
|
-
return this.browser.waitUntil(
|
|
2368
|
-
|
|
2369
|
-
|
|
2370
|
-
|
|
2371
|
-
|
|
2372
|
-
|
|
2373
|
-
|
|
2374
|
-
|
|
2375
|
-
|
|
2467
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds
|
|
2468
|
+
|
|
2469
|
+
return this.browser.waitUntil(
|
|
2470
|
+
async () => {
|
|
2471
|
+
const res = await this._res(locator)
|
|
2472
|
+
if (!res || res.length === 0) return false
|
|
2473
|
+
const selected = await forEachAsync(res, async (el) => el.isDisplayed())
|
|
2474
|
+
if (Array.isArray(selected)) {
|
|
2475
|
+
return selected.filter((val) => val === true).length > 0
|
|
2476
|
+
}
|
|
2477
|
+
return selected
|
|
2478
|
+
},
|
|
2479
|
+
{
|
|
2480
|
+
timeout: aSec * 1000,
|
|
2481
|
+
timeoutMsg: `element (${new Locator(locator)}) still not visible after ${aSec} sec`,
|
|
2482
|
+
},
|
|
2483
|
+
)
|
|
2376
2484
|
}
|
|
2377
2485
|
|
|
2378
2486
|
/**
|
|
2379
2487
|
* {{> waitNumberOfVisibleElements }}
|
|
2380
2488
|
*/
|
|
2381
2489
|
async waitNumberOfVisibleElements(locator, num, sec = null) {
|
|
2382
|
-
const aSec = sec || this.options.waitForTimeoutInSeconds
|
|
2490
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds
|
|
2383
2491
|
|
|
2384
|
-
return this.browser.waitUntil(
|
|
2385
|
-
|
|
2386
|
-
|
|
2387
|
-
|
|
2492
|
+
return this.browser.waitUntil(
|
|
2493
|
+
async () => {
|
|
2494
|
+
const res = await this._res(locator)
|
|
2495
|
+
if (!res || res.length === 0) return false
|
|
2496
|
+
let selected = await forEachAsync(res, async (el) => el.isDisplayed())
|
|
2388
2497
|
|
|
2389
|
-
|
|
2390
|
-
|
|
2391
|
-
|
|
2392
|
-
|
|
2498
|
+
if (!Array.isArray(selected)) selected = [selected]
|
|
2499
|
+
selected = selected.filter((val) => val === true)
|
|
2500
|
+
return selected.length === num
|
|
2501
|
+
},
|
|
2502
|
+
{
|
|
2503
|
+
timeout: aSec * 1000,
|
|
2504
|
+
timeoutMsg: `The number of elements (${new Locator(locator)}) is not ${num} after ${aSec} sec`,
|
|
2505
|
+
},
|
|
2506
|
+
)
|
|
2393
2507
|
}
|
|
2394
2508
|
|
|
2395
2509
|
/**
|
|
2396
2510
|
* {{> waitForInvisible }}
|
|
2397
2511
|
*/
|
|
2398
2512
|
async waitForInvisible(locator, sec = null) {
|
|
2399
|
-
const aSec = sec || this.options.waitForTimeoutInSeconds
|
|
2400
|
-
|
|
2401
|
-
return this.browser.waitUntil(
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
|
|
2513
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds
|
|
2514
|
+
|
|
2515
|
+
return this.browser.waitUntil(
|
|
2516
|
+
async () => {
|
|
2517
|
+
const res = await this._res(locator)
|
|
2518
|
+
if (!res || res.length === 0) return true
|
|
2519
|
+
const selected = await forEachAsync(res, async (el) => el.isDisplayed())
|
|
2520
|
+
return !selected.length
|
|
2521
|
+
},
|
|
2522
|
+
{ timeout: aSec * 1000, timeoutMsg: `element (${new Locator(locator)}) still visible after ${aSec} sec` },
|
|
2523
|
+
)
|
|
2407
2524
|
}
|
|
2408
2525
|
|
|
2409
2526
|
/**
|
|
2410
2527
|
* {{> waitToHide }}
|
|
2411
2528
|
*/
|
|
2412
2529
|
async waitToHide(locator, sec = null) {
|
|
2413
|
-
return this.waitForInvisible(locator, sec)
|
|
2530
|
+
return this.waitForInvisible(locator, sec)
|
|
2414
2531
|
}
|
|
2415
2532
|
|
|
2416
2533
|
/**
|
|
2417
2534
|
* {{> waitForDetached }}
|
|
2418
2535
|
*/
|
|
2419
2536
|
async waitForDetached(locator, sec = null) {
|
|
2420
|
-
const aSec = sec || this.options.waitForTimeoutInSeconds
|
|
2537
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds
|
|
2421
2538
|
|
|
2422
|
-
return this.browser.waitUntil(
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2539
|
+
return this.browser.waitUntil(
|
|
2540
|
+
async () => {
|
|
2541
|
+
const res = await this._res(locator)
|
|
2542
|
+
if (!res || res.length === 0) {
|
|
2543
|
+
return true
|
|
2544
|
+
}
|
|
2545
|
+
return false
|
|
2546
|
+
},
|
|
2547
|
+
{ timeout: aSec * 1000, timeoutMsg: `element (${new Locator(locator)}) still on page after ${aSec} sec` },
|
|
2548
|
+
)
|
|
2429
2549
|
}
|
|
2430
2550
|
|
|
2431
2551
|
/**
|
|
2432
2552
|
* {{> waitForFunction }}
|
|
2433
2553
|
*/
|
|
2434
2554
|
async waitForFunction(fn, argsOrSec = null, sec = null) {
|
|
2435
|
-
let args = []
|
|
2555
|
+
let args = []
|
|
2436
2556
|
if (argsOrSec) {
|
|
2437
2557
|
if (Array.isArray(argsOrSec)) {
|
|
2438
|
-
args = argsOrSec
|
|
2558
|
+
args = argsOrSec
|
|
2439
2559
|
} else if (typeof argsOrSec === 'number') {
|
|
2440
|
-
sec = argsOrSec
|
|
2560
|
+
sec = argsOrSec
|
|
2441
2561
|
}
|
|
2442
2562
|
}
|
|
2443
2563
|
|
|
2444
|
-
const aSec = sec || this.options.waitForTimeoutInSeconds
|
|
2564
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds
|
|
2445
2565
|
|
|
2446
|
-
return this.browser.waitUntil(async () => this.browser.execute(fn, ...args), {
|
|
2566
|
+
return this.browser.waitUntil(async () => this.browser.execute(fn, ...args), {
|
|
2567
|
+
timeout: aSec * 1000,
|
|
2568
|
+
timeoutMsg: '',
|
|
2569
|
+
})
|
|
2447
2570
|
}
|
|
2448
2571
|
|
|
2449
2572
|
/**
|
|
2450
2573
|
* {{> waitForNumberOfTabs }}
|
|
2451
2574
|
*/
|
|
2452
2575
|
async waitForNumberOfTabs(expectedTabs, sec) {
|
|
2453
|
-
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeoutInSeconds
|
|
2454
|
-
let currentTabs
|
|
2455
|
-
let count = 0
|
|
2576
|
+
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeoutInSeconds
|
|
2577
|
+
let currentTabs
|
|
2578
|
+
let count = 0
|
|
2456
2579
|
|
|
2457
2580
|
do {
|
|
2458
|
-
currentTabs = await this.grabNumberOfOpenTabs()
|
|
2459
|
-
await this.wait(1)
|
|
2460
|
-
count += 1000
|
|
2461
|
-
if (currentTabs >= expectedTabs) return
|
|
2462
|
-
} while (count <= waitTimeout)
|
|
2581
|
+
currentTabs = await this.grabNumberOfOpenTabs()
|
|
2582
|
+
await this.wait(1)
|
|
2583
|
+
count += 1000
|
|
2584
|
+
if (currentTabs >= expectedTabs) return
|
|
2585
|
+
} while (count <= waitTimeout)
|
|
2463
2586
|
|
|
2464
|
-
throw new Error(`Expected ${expectedTabs} tabs are not met after ${waitTimeout / 1000} sec.`)
|
|
2587
|
+
throw new Error(`Expected ${expectedTabs} tabs are not met after ${waitTimeout / 1000} sec.`)
|
|
2465
2588
|
}
|
|
2466
2589
|
|
|
2467
2590
|
/**
|
|
2468
2591
|
* {{> switchTo }}
|
|
2469
2592
|
*/
|
|
2470
2593
|
async switchTo(locator) {
|
|
2471
|
-
this.browser.isInsideFrame = true
|
|
2594
|
+
this.browser.isInsideFrame = true
|
|
2472
2595
|
if (Number.isInteger(locator)) {
|
|
2473
2596
|
if (this.options.automationProtocol) {
|
|
2474
|
-
return this.browser.switchToFrame(locator + 1)
|
|
2597
|
+
return this.browser.switchToFrame(locator + 1)
|
|
2475
2598
|
}
|
|
2476
|
-
return this.browser.switchToFrame(locator)
|
|
2599
|
+
return this.browser.switchToFrame(locator)
|
|
2477
2600
|
}
|
|
2478
2601
|
if (!locator) {
|
|
2479
|
-
return this.browser.switchToFrame(null)
|
|
2602
|
+
return this.browser.switchToFrame(null)
|
|
2480
2603
|
}
|
|
2481
2604
|
|
|
2482
|
-
let res = await this._locate(locator, true)
|
|
2483
|
-
assertElementExists(res, locator)
|
|
2484
|
-
res = usingFirstElement(res)
|
|
2485
|
-
return this.browser.switchToFrame(res)
|
|
2605
|
+
let res = await this._locate(locator, true)
|
|
2606
|
+
assertElementExists(res, locator)
|
|
2607
|
+
res = usingFirstElement(res)
|
|
2608
|
+
return this.browser.switchToFrame(res)
|
|
2486
2609
|
}
|
|
2487
2610
|
|
|
2488
2611
|
/**
|
|
2489
2612
|
* {{> switchToNextTab }}
|
|
2490
2613
|
*/
|
|
2491
2614
|
async switchToNextTab(num = 1, sec = null) {
|
|
2492
|
-
const aSec = sec || this.options.waitForTimeoutInSeconds
|
|
2493
|
-
let target
|
|
2494
|
-
const current = await this.browser.getWindowHandle()
|
|
2495
|
-
|
|
2496
|
-
await this.browser.waitUntil(
|
|
2497
|
-
|
|
2498
|
-
|
|
2499
|
-
|
|
2500
|
-
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2615
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds
|
|
2616
|
+
let target
|
|
2617
|
+
const current = await this.browser.getWindowHandle()
|
|
2618
|
+
|
|
2619
|
+
await this.browser.waitUntil(
|
|
2620
|
+
async () => {
|
|
2621
|
+
await this.browser.getWindowHandles().then((handles) => {
|
|
2622
|
+
if (handles.indexOf(current) + num + 1 <= handles.length) {
|
|
2623
|
+
target = handles[handles.indexOf(current) + num]
|
|
2624
|
+
}
|
|
2625
|
+
})
|
|
2626
|
+
return target
|
|
2627
|
+
},
|
|
2628
|
+
{ timeout: aSec * 1000, timeoutMsg: `There is no ability to switch to next tab with offset ${num}` },
|
|
2629
|
+
)
|
|
2630
|
+
return this.browser.switchToWindow(target)
|
|
2505
2631
|
}
|
|
2506
2632
|
|
|
2507
2633
|
/**
|
|
2508
2634
|
* {{> switchToPreviousTab }}
|
|
2509
2635
|
*/
|
|
2510
2636
|
async switchToPreviousTab(num = 1, sec = null) {
|
|
2511
|
-
const aSec = sec || this.options.waitForTimeoutInSeconds
|
|
2512
|
-
const current = await this.browser.getWindowHandle()
|
|
2513
|
-
let target
|
|
2514
|
-
|
|
2515
|
-
await this.browser.waitUntil(
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2637
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds
|
|
2638
|
+
const current = await this.browser.getWindowHandle()
|
|
2639
|
+
let target
|
|
2640
|
+
|
|
2641
|
+
await this.browser.waitUntil(
|
|
2642
|
+
async () => {
|
|
2643
|
+
await this.browser.getWindowHandles().then((handles) => {
|
|
2644
|
+
if (handles.indexOf(current) - num > -1) {
|
|
2645
|
+
target = handles[handles.indexOf(current) - num]
|
|
2646
|
+
}
|
|
2647
|
+
})
|
|
2648
|
+
return target
|
|
2649
|
+
},
|
|
2650
|
+
{ timeout: aSec * 1000, timeoutMsg: `There is no ability to switch to previous tab with offset ${num}` },
|
|
2651
|
+
)
|
|
2652
|
+
return this.browser.switchToWindow(target)
|
|
2524
2653
|
}
|
|
2525
2654
|
|
|
2526
2655
|
/**
|
|
2527
2656
|
* {{> closeCurrentTab }}
|
|
2528
2657
|
*/
|
|
2529
2658
|
async closeCurrentTab() {
|
|
2530
|
-
await this.browser.closeWindow()
|
|
2531
|
-
const handles = await this.browser.getWindowHandles()
|
|
2532
|
-
if (handles[0]) await this.browser.switchToWindow(handles[0])
|
|
2659
|
+
await this.browser.closeWindow()
|
|
2660
|
+
const handles = await this.browser.getWindowHandles()
|
|
2661
|
+
if (handles[0]) await this.browser.switchToWindow(handles[0])
|
|
2533
2662
|
}
|
|
2534
2663
|
|
|
2535
2664
|
/**
|
|
2536
2665
|
* {{> openNewTab }}
|
|
2537
2666
|
*/
|
|
2538
2667
|
async openNewTab(url = 'about:blank', windowName = null) {
|
|
2539
|
-
const client = this.browser
|
|
2540
|
-
const crypto = require('crypto')
|
|
2668
|
+
const client = this.browser
|
|
2669
|
+
const crypto = require('crypto')
|
|
2541
2670
|
if (windowName == null) {
|
|
2542
|
-
windowName = crypto.randomBytes(32).toString('hex')
|
|
2671
|
+
windowName = crypto.randomBytes(32).toString('hex')
|
|
2543
2672
|
}
|
|
2544
|
-
return client.newWindow(url, windowName)
|
|
2673
|
+
return client.newWindow(url, windowName)
|
|
2545
2674
|
}
|
|
2546
2675
|
|
|
2547
2676
|
/**
|
|
2548
2677
|
* {{> grabNumberOfOpenTabs }}
|
|
2549
2678
|
*/
|
|
2550
2679
|
async grabNumberOfOpenTabs() {
|
|
2551
|
-
const pages = await this.browser.getWindowHandles()
|
|
2552
|
-
this.debugSection('Tabs', `Total ${pages.length}`)
|
|
2553
|
-
return pages.length
|
|
2680
|
+
const pages = await this.browser.getWindowHandles()
|
|
2681
|
+
this.debugSection('Tabs', `Total ${pages.length}`)
|
|
2682
|
+
return pages.length
|
|
2554
2683
|
}
|
|
2555
2684
|
|
|
2556
2685
|
/**
|
|
2557
2686
|
* {{> refreshPage }}
|
|
2558
2687
|
*/
|
|
2559
2688
|
async refreshPage() {
|
|
2560
|
-
const client = this.browser
|
|
2561
|
-
return client.refresh()
|
|
2689
|
+
const client = this.browser
|
|
2690
|
+
return client.refresh()
|
|
2562
2691
|
}
|
|
2563
2692
|
|
|
2564
2693
|
/**
|
|
2565
2694
|
* {{> scrollPageToTop }}
|
|
2566
2695
|
*/
|
|
2567
2696
|
scrollPageToTop() {
|
|
2568
|
-
const client = this.browser
|
|
2697
|
+
const client = this.browser
|
|
2569
2698
|
/* eslint-disable prefer-arrow-callback */
|
|
2570
2699
|
return client.execute(function () {
|
|
2571
|
-
window.scrollTo(0, 0)
|
|
2572
|
-
})
|
|
2700
|
+
window.scrollTo(0, 0)
|
|
2701
|
+
})
|
|
2573
2702
|
/* eslint-enable */
|
|
2574
2703
|
}
|
|
2575
2704
|
|
|
@@ -2577,19 +2706,16 @@ class WebDriver extends Helper {
|
|
|
2577
2706
|
* {{> scrollPageToBottom }}
|
|
2578
2707
|
*/
|
|
2579
2708
|
scrollPageToBottom() {
|
|
2580
|
-
const client = this.browser
|
|
2709
|
+
const client = this.browser
|
|
2581
2710
|
/* eslint-disable prefer-arrow-callback, comma-dangle */
|
|
2582
2711
|
return client.execute(function () {
|
|
2583
|
-
const body = document.body
|
|
2584
|
-
const html = document.documentElement
|
|
2585
|
-
window.scrollTo(
|
|
2586
|
-
|
|
2587
|
-
body.offsetHeight,
|
|
2588
|
-
|
|
2589
|
-
|
|
2590
|
-
html.offsetHeight
|
|
2591
|
-
));
|
|
2592
|
-
});
|
|
2712
|
+
const body = document.body
|
|
2713
|
+
const html = document.documentElement
|
|
2714
|
+
window.scrollTo(
|
|
2715
|
+
0,
|
|
2716
|
+
Math.max(body.scrollHeight, body.offsetHeight, html.clientHeight, html.scrollHeight, html.offsetHeight),
|
|
2717
|
+
)
|
|
2718
|
+
})
|
|
2593
2719
|
/* eslint-enable */
|
|
2594
2720
|
}
|
|
2595
2721
|
|
|
@@ -2601,11 +2727,11 @@ class WebDriver extends Helper {
|
|
|
2601
2727
|
function getScrollPosition() {
|
|
2602
2728
|
return {
|
|
2603
2729
|
x: window.pageXOffset,
|
|
2604
|
-
y: window.pageYOffset
|
|
2605
|
-
}
|
|
2730
|
+
y: window.pageYOffset,
|
|
2731
|
+
}
|
|
2606
2732
|
}
|
|
2607
2733
|
/* eslint-enable comma-dangle */
|
|
2608
|
-
return this.executeScript(getScrollPosition)
|
|
2734
|
+
return this.executeScript(getScrollPosition)
|
|
2609
2735
|
}
|
|
2610
2736
|
|
|
2611
2737
|
/**
|
|
@@ -2618,15 +2744,15 @@ class WebDriver extends Helper {
|
|
|
2618
2744
|
if (!this.options.automationProtocol) {
|
|
2619
2745
|
console.log(`setGeoLocation deprecated:
|
|
2620
2746
|
* This command is deprecated due to using deprecated JSON Wire Protocol command. More info: https://webdriver.io/docs/api/jsonwp/#setgeolocation
|
|
2621
|
-
* Switch to devtools protocol to use this command by setting devtoolsProtocol: true in the configuration`)
|
|
2622
|
-
return
|
|
2747
|
+
* Switch to devtools protocol to use this command by setting devtoolsProtocol: true in the configuration`)
|
|
2748
|
+
return
|
|
2623
2749
|
}
|
|
2624
|
-
this.geoLocation = { latitude, longitude }
|
|
2750
|
+
this.geoLocation = { latitude, longitude }
|
|
2625
2751
|
|
|
2626
2752
|
await this.browser.call(async () => {
|
|
2627
|
-
const pages = await this.puppeteerBrowser.pages()
|
|
2628
|
-
await pages[0].setGeolocation({ latitude, longitude })
|
|
2629
|
-
})
|
|
2753
|
+
const pages = await this.puppeteerBrowser.pages()
|
|
2754
|
+
await pages[0].setGeolocation({ latitude, longitude })
|
|
2755
|
+
})
|
|
2630
2756
|
}
|
|
2631
2757
|
|
|
2632
2758
|
/**
|
|
@@ -2639,27 +2765,27 @@ class WebDriver extends Helper {
|
|
|
2639
2765
|
if (!this.options.automationProtocol) {
|
|
2640
2766
|
console.log(`grabGeoLocation deprecated:
|
|
2641
2767
|
* This command is deprecated due to using deprecated JSON Wire Protocol command. More info: https://webdriver.io/docs/api/jsonwp/#getgeolocation
|
|
2642
|
-
* Switch to devtools protocol to use this command by setting devtoolsProtocol: true in the configuration`)
|
|
2643
|
-
return
|
|
2768
|
+
* Switch to devtools protocol to use this command by setting devtoolsProtocol: true in the configuration`)
|
|
2769
|
+
return
|
|
2644
2770
|
}
|
|
2645
|
-
if (!this.geoLocation) return 'No GeoLocation is set!'
|
|
2646
|
-
return this.geoLocation
|
|
2771
|
+
if (!this.geoLocation) return 'No GeoLocation is set!'
|
|
2772
|
+
return this.geoLocation
|
|
2647
2773
|
}
|
|
2648
2774
|
|
|
2649
2775
|
/**
|
|
2650
2776
|
* {{> grabElementBoundingRect }}
|
|
2651
2777
|
*/
|
|
2652
2778
|
async grabElementBoundingRect(locator, prop) {
|
|
2653
|
-
const res = await this._locate(locator, true)
|
|
2654
|
-
assertElementExists(res, locator)
|
|
2655
|
-
const el = usingFirstElement(res)
|
|
2779
|
+
const res = await this._locate(locator, true)
|
|
2780
|
+
assertElementExists(res, locator)
|
|
2781
|
+
const el = usingFirstElement(res)
|
|
2656
2782
|
|
|
2657
2783
|
const rect = {
|
|
2658
|
-
...await el.getLocation(),
|
|
2659
|
-
...await el.getSize(),
|
|
2660
|
-
}
|
|
2661
|
-
if (prop) return rect[prop]
|
|
2662
|
-
return rect
|
|
2784
|
+
...(await el.getLocation()),
|
|
2785
|
+
...(await el.getSize()),
|
|
2786
|
+
}
|
|
2787
|
+
if (prop) return rect[prop]
|
|
2788
|
+
return rect
|
|
2663
2789
|
}
|
|
2664
2790
|
|
|
2665
2791
|
/**
|
|
@@ -2668,23 +2794,21 @@ class WebDriver extends Helper {
|
|
|
2668
2794
|
* @param {*} fn
|
|
2669
2795
|
*/
|
|
2670
2796
|
/* eslint-disable */
|
|
2671
|
-
runOnIOS(caps, fn) {
|
|
2672
|
-
}
|
|
2797
|
+
runOnIOS(caps, fn) {}
|
|
2673
2798
|
|
|
2674
2799
|
/**
|
|
2675
2800
|
* Placeholder for ~ locator only test case write once run on both Appium and WebDriver.
|
|
2676
2801
|
* @param {*} caps
|
|
2677
2802
|
* @param {*} fn
|
|
2678
2803
|
*/
|
|
2679
|
-
runOnAndroid(caps, fn) {
|
|
2680
|
-
}
|
|
2804
|
+
runOnAndroid(caps, fn) {}
|
|
2681
2805
|
/* eslint-enable */
|
|
2682
2806
|
|
|
2683
2807
|
/**
|
|
2684
2808
|
* Placeholder for ~ locator only test case write once run on both Appium and WebDriver.
|
|
2685
2809
|
*/
|
|
2686
2810
|
runInWeb(fn) {
|
|
2687
|
-
return fn()
|
|
2811
|
+
return fn()
|
|
2688
2812
|
}
|
|
2689
2813
|
|
|
2690
2814
|
/**
|
|
@@ -2695,10 +2819,12 @@ class WebDriver extends Helper {
|
|
|
2695
2819
|
*/
|
|
2696
2820
|
flushNetworkTraffics() {
|
|
2697
2821
|
if (!this.options.automationProtocol) {
|
|
2698
|
-
console.log(
|
|
2699
|
-
|
|
2822
|
+
console.log(
|
|
2823
|
+
'* Switch to devtools protocol to use this command by setting devtoolsProtocol: true in the configuration',
|
|
2824
|
+
)
|
|
2825
|
+
return
|
|
2700
2826
|
}
|
|
2701
|
-
this.requests = []
|
|
2827
|
+
this.requests = []
|
|
2702
2828
|
}
|
|
2703
2829
|
|
|
2704
2830
|
/**
|
|
@@ -2709,11 +2835,13 @@ class WebDriver extends Helper {
|
|
|
2709
2835
|
*/
|
|
2710
2836
|
stopRecordingTraffic() {
|
|
2711
2837
|
if (!this.options.automationProtocol) {
|
|
2712
|
-
console.log(
|
|
2713
|
-
|
|
2838
|
+
console.log(
|
|
2839
|
+
'* Switch to devtools protocol to use this command by setting devtoolsProtocol: true in the configuration',
|
|
2840
|
+
)
|
|
2841
|
+
return
|
|
2714
2842
|
}
|
|
2715
|
-
this.page.removeAllListeners('request')
|
|
2716
|
-
this.recording = false
|
|
2843
|
+
this.page.removeAllListeners('request')
|
|
2844
|
+
this.recording = false
|
|
2717
2845
|
}
|
|
2718
2846
|
|
|
2719
2847
|
/**
|
|
@@ -2725,14 +2853,16 @@ class WebDriver extends Helper {
|
|
|
2725
2853
|
*/
|
|
2726
2854
|
async startRecordingTraffic() {
|
|
2727
2855
|
if (!this.options.automationProtocol) {
|
|
2728
|
-
console.log(
|
|
2729
|
-
|
|
2856
|
+
console.log(
|
|
2857
|
+
'* Switch to devtools protocol to use this command by setting devtoolsProtocol: true in the configuration',
|
|
2858
|
+
)
|
|
2859
|
+
return
|
|
2730
2860
|
}
|
|
2731
|
-
this.flushNetworkTraffics()
|
|
2732
|
-
this.recording = true
|
|
2733
|
-
this.recordedAtLeastOnce = true
|
|
2861
|
+
this.flushNetworkTraffics()
|
|
2862
|
+
this.recording = true
|
|
2863
|
+
this.recordedAtLeastOnce = true
|
|
2734
2864
|
|
|
2735
|
-
await this.page.setRequestInterception(true)
|
|
2865
|
+
await this.page.setRequestInterception(true)
|
|
2736
2866
|
|
|
2737
2867
|
this.page.on('request', (request) => {
|
|
2738
2868
|
const information = {
|
|
@@ -2741,16 +2871,16 @@ class WebDriver extends Helper {
|
|
|
2741
2871
|
requestHeaders: request.headers(),
|
|
2742
2872
|
requestPostData: request.postData(),
|
|
2743
2873
|
response: request.response(),
|
|
2744
|
-
}
|
|
2874
|
+
}
|
|
2745
2875
|
|
|
2746
|
-
this.debugSection('REQUEST: ', JSON.stringify(information))
|
|
2876
|
+
this.debugSection('REQUEST: ', JSON.stringify(information))
|
|
2747
2877
|
|
|
2748
2878
|
if (typeof information.requestPostData === 'object') {
|
|
2749
|
-
information.requestPostData = JSON.parse(information.requestPostData)
|
|
2879
|
+
information.requestPostData = JSON.parse(information.requestPostData)
|
|
2750
2880
|
}
|
|
2751
|
-
request.continue()
|
|
2752
|
-
this.requests.push(information)
|
|
2753
|
-
})
|
|
2881
|
+
request.continue()
|
|
2882
|
+
this.requests.push(information)
|
|
2883
|
+
})
|
|
2754
2884
|
}
|
|
2755
2885
|
|
|
2756
2886
|
/**
|
|
@@ -2761,10 +2891,12 @@ class WebDriver extends Helper {
|
|
|
2761
2891
|
*/
|
|
2762
2892
|
async grabRecordedNetworkTraffics() {
|
|
2763
2893
|
if (!this.options.automationProtocol) {
|
|
2764
|
-
console.log(
|
|
2765
|
-
|
|
2894
|
+
console.log(
|
|
2895
|
+
'* Switch to devtools protocol to use this command by setting devtoolsProtocol: true in the configuration',
|
|
2896
|
+
)
|
|
2897
|
+
return
|
|
2766
2898
|
}
|
|
2767
|
-
return grabRecordedNetworkTraffics.call(this)
|
|
2899
|
+
return grabRecordedNetworkTraffics.call(this)
|
|
2768
2900
|
}
|
|
2769
2901
|
|
|
2770
2902
|
/**
|
|
@@ -2773,14 +2905,14 @@ class WebDriver extends Helper {
|
|
|
2773
2905
|
*
|
|
2774
2906
|
* {{> seeTraffic }}
|
|
2775
2907
|
*/
|
|
2776
|
-
async seeTraffic({
|
|
2777
|
-
name, url, parameters, requestPostData, timeout = 10,
|
|
2778
|
-
}) {
|
|
2908
|
+
async seeTraffic({ name, url, parameters, requestPostData, timeout = 10 }) {
|
|
2779
2909
|
if (!this.options.automationProtocol) {
|
|
2780
|
-
console.log(
|
|
2781
|
-
|
|
2910
|
+
console.log(
|
|
2911
|
+
'* Switch to devtools protocol to use this command by setting devtoolsProtocol: true in the configuration',
|
|
2912
|
+
)
|
|
2913
|
+
return
|
|
2782
2914
|
}
|
|
2783
|
-
await seeTraffic.call(this, ...arguments)
|
|
2915
|
+
await seeTraffic.call(this, ...arguments)
|
|
2784
2916
|
}
|
|
2785
2917
|
|
|
2786
2918
|
/**
|
|
@@ -2792,38 +2924,40 @@ class WebDriver extends Helper {
|
|
|
2792
2924
|
*/
|
|
2793
2925
|
dontSeeTraffic({ name, url }) {
|
|
2794
2926
|
if (!this.options.automationProtocol) {
|
|
2795
|
-
console.log(
|
|
2796
|
-
|
|
2927
|
+
console.log(
|
|
2928
|
+
'* Switch to devtools protocol to use this command by setting devtoolsProtocol: true in the configuration',
|
|
2929
|
+
)
|
|
2930
|
+
return
|
|
2797
2931
|
}
|
|
2798
|
-
dontSeeTraffic.call(this, ...arguments)
|
|
2932
|
+
dontSeeTraffic.call(this, ...arguments)
|
|
2799
2933
|
}
|
|
2800
2934
|
}
|
|
2801
2935
|
|
|
2802
2936
|
async function proceedSee(assertType, text, context, strict = false) {
|
|
2803
|
-
let description
|
|
2937
|
+
let description
|
|
2804
2938
|
if (!context) {
|
|
2805
2939
|
if (this.context === webRoot) {
|
|
2806
|
-
context = this.context
|
|
2807
|
-
description = 'web page'
|
|
2940
|
+
context = this.context
|
|
2941
|
+
description = 'web page'
|
|
2808
2942
|
} else {
|
|
2809
|
-
description = `current context ${this.context}
|
|
2810
|
-
context = './/*'
|
|
2943
|
+
description = `current context ${this.context}`
|
|
2944
|
+
context = './/*'
|
|
2811
2945
|
}
|
|
2812
2946
|
} else {
|
|
2813
|
-
description = `element ${context}
|
|
2947
|
+
description = `element ${context}`
|
|
2814
2948
|
}
|
|
2815
2949
|
|
|
2816
|
-
const smartWaitEnabled = assertType === 'assert'
|
|
2817
|
-
const res = await this._locate(withStrictLocator(context), smartWaitEnabled)
|
|
2818
|
-
assertElementExists(res, context)
|
|
2819
|
-
const selected = await forEachAsync(res, async el => this.browser.getElementText(getElementId(el)))
|
|
2950
|
+
const smartWaitEnabled = assertType === 'assert'
|
|
2951
|
+
const res = await this._locate(withStrictLocator(context), smartWaitEnabled)
|
|
2952
|
+
assertElementExists(res, context)
|
|
2953
|
+
const selected = await forEachAsync(res, async (el) => this.browser.getElementText(getElementId(el)))
|
|
2820
2954
|
if (strict) {
|
|
2821
2955
|
if (Array.isArray(selected) && selected.length !== 0) {
|
|
2822
|
-
return selected.map(elText => equals(description)[assertType](text, elText))
|
|
2956
|
+
return selected.map((elText) => equals(description)[assertType](text, elText))
|
|
2823
2957
|
}
|
|
2824
|
-
return equals(description)[assertType](text, selected)
|
|
2958
|
+
return equals(description)[assertType](text, selected)
|
|
2825
2959
|
}
|
|
2826
|
-
return stringIncludes(description)[assertType](text, selected)
|
|
2960
|
+
return stringIncludes(description)[assertType](text, selected)
|
|
2827
2961
|
}
|
|
2828
2962
|
|
|
2829
2963
|
/**
|
|
@@ -2840,21 +2974,19 @@ async function proceedSee(assertType, text, context, strict = false) {
|
|
|
2840
2974
|
* @return {Promise<Array>} - Array of values.
|
|
2841
2975
|
*/
|
|
2842
2976
|
async function forEachAsync(array, callback, options = { expandArrayResults: true }) {
|
|
2843
|
-
const {
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
const inputArray = Array.isArray(array) ? array : [array];
|
|
2847
|
-
const values = [];
|
|
2977
|
+
const { expandArrayResults = true } = options
|
|
2978
|
+
const inputArray = Array.isArray(array) ? array : [array]
|
|
2979
|
+
const values = []
|
|
2848
2980
|
for (let index = 0; index < inputArray.length; index++) {
|
|
2849
|
-
const res = await callback(inputArray[index], index, inputArray)
|
|
2981
|
+
const res = await callback(inputArray[index], index, inputArray)
|
|
2850
2982
|
|
|
2851
2983
|
if (Array.isArray(res) && expandArrayResults) {
|
|
2852
|
-
res.forEach(val => values.push(val))
|
|
2984
|
+
res.forEach((val) => values.push(val))
|
|
2853
2985
|
} else if (res) {
|
|
2854
|
-
values.push(res)
|
|
2986
|
+
values.push(res)
|
|
2855
2987
|
}
|
|
2856
2988
|
}
|
|
2857
|
-
return values
|
|
2989
|
+
return values
|
|
2858
2990
|
}
|
|
2859
2991
|
|
|
2860
2992
|
/**
|
|
@@ -2869,374 +3001,380 @@ async function forEachAsync(array, callback, options = { expandArrayResults: tru
|
|
|
2869
3001
|
* @return {Promise<Array>} - Array of values.
|
|
2870
3002
|
*/
|
|
2871
3003
|
async function filterAsync(array, callback) {
|
|
2872
|
-
const inputArray = Array.isArray(array) ? array : [array]
|
|
2873
|
-
const values = []
|
|
3004
|
+
const inputArray = Array.isArray(array) ? array : [array]
|
|
3005
|
+
const values = []
|
|
2874
3006
|
for (let index = 0; index < inputArray.length; index++) {
|
|
2875
|
-
const res = await callback(inputArray[index], index, inputArray)
|
|
2876
|
-
const value = Array.isArray(res) ? res[0] : res
|
|
3007
|
+
const res = await callback(inputArray[index], index, inputArray)
|
|
3008
|
+
const value = Array.isArray(res) ? res[0] : res
|
|
2877
3009
|
|
|
2878
3010
|
if (value) {
|
|
2879
|
-
values.push(inputArray[index])
|
|
3011
|
+
values.push(inputArray[index])
|
|
2880
3012
|
}
|
|
2881
3013
|
}
|
|
2882
|
-
return values
|
|
3014
|
+
return values
|
|
2883
3015
|
}
|
|
2884
3016
|
|
|
2885
3017
|
async function findClickable(locator, locateFn) {
|
|
2886
|
-
locator = new Locator(locator)
|
|
3018
|
+
locator = new Locator(locator)
|
|
2887
3019
|
|
|
2888
3020
|
if (this._isCustomLocator(locator)) {
|
|
2889
|
-
return locateFn(locator.value)
|
|
3021
|
+
return locateFn(locator.value)
|
|
2890
3022
|
}
|
|
2891
3023
|
|
|
2892
|
-
if (locator.isAccessibilityId() && !this.isWeb) return locateFn(locator, true)
|
|
2893
|
-
if (!locator.isFuzzy()) return locateFn(locator, true)
|
|
3024
|
+
if (locator.isAccessibilityId() && !this.isWeb) return locateFn(locator, true)
|
|
3025
|
+
if (!locator.isFuzzy()) return locateFn(locator, true)
|
|
2894
3026
|
|
|
2895
|
-
let els
|
|
2896
|
-
const literal = xpathLocator.literal(locator.value)
|
|
3027
|
+
let els
|
|
3028
|
+
const literal = xpathLocator.literal(locator.value)
|
|
2897
3029
|
|
|
2898
|
-
els = await locateFn(Locator.clickable.narrow(literal))
|
|
2899
|
-
if (els.length) return els
|
|
3030
|
+
els = await locateFn(Locator.clickable.narrow(literal))
|
|
3031
|
+
if (els.length) return els
|
|
2900
3032
|
|
|
2901
|
-
els = await locateFn(Locator.clickable.wide(literal))
|
|
2902
|
-
if (els.length) return els
|
|
3033
|
+
els = await locateFn(Locator.clickable.wide(literal))
|
|
3034
|
+
if (els.length) return els
|
|
2903
3035
|
|
|
2904
|
-
els = await locateFn(Locator.clickable.self(literal))
|
|
2905
|
-
if (els.length) return els
|
|
3036
|
+
els = await locateFn(Locator.clickable.self(literal))
|
|
3037
|
+
if (els.length) return els
|
|
2906
3038
|
|
|
2907
|
-
return locateFn(locator.value)
|
|
3039
|
+
return locateFn(locator.value) // by css or xpath
|
|
2908
3040
|
}
|
|
2909
3041
|
|
|
2910
3042
|
async function findFields(locator) {
|
|
2911
|
-
locator = new Locator(locator)
|
|
3043
|
+
locator = new Locator(locator)
|
|
2912
3044
|
|
|
2913
3045
|
if (this._isCustomLocator(locator)) {
|
|
2914
|
-
return this._locate(locator)
|
|
3046
|
+
return this._locate(locator)
|
|
2915
3047
|
}
|
|
2916
3048
|
|
|
2917
|
-
if (locator.isAccessibilityId() && !this.isWeb) return this._locate(locator, true)
|
|
2918
|
-
if (!locator.isFuzzy()) return this._locate(locator, true)
|
|
3049
|
+
if (locator.isAccessibilityId() && !this.isWeb) return this._locate(locator, true)
|
|
3050
|
+
if (!locator.isFuzzy()) return this._locate(locator, true)
|
|
2919
3051
|
|
|
2920
|
-
const literal = xpathLocator.literal(locator.value)
|
|
2921
|
-
let els = await this._locate(Locator.field.labelEquals(literal))
|
|
2922
|
-
if (els.length) return els
|
|
3052
|
+
const literal = xpathLocator.literal(locator.value)
|
|
3053
|
+
let els = await this._locate(Locator.field.labelEquals(literal))
|
|
3054
|
+
if (els.length) return els
|
|
2923
3055
|
|
|
2924
|
-
els = await this._locate(Locator.field.labelContains(literal))
|
|
2925
|
-
if (els.length) return els
|
|
3056
|
+
els = await this._locate(Locator.field.labelContains(literal))
|
|
3057
|
+
if (els.length) return els
|
|
2926
3058
|
|
|
2927
|
-
els = await this._locate(Locator.field.byName(literal))
|
|
2928
|
-
if (els.length) return els
|
|
2929
|
-
return this._locate(locator.value)
|
|
3059
|
+
els = await this._locate(Locator.field.byName(literal))
|
|
3060
|
+
if (els.length) return els
|
|
3061
|
+
return this._locate(locator.value) // by css or xpath
|
|
2930
3062
|
}
|
|
2931
3063
|
|
|
2932
3064
|
async function proceedSeeField(assertType, field, value) {
|
|
2933
|
-
const res = await findFields.call(this, field)
|
|
2934
|
-
assertElementExists(res, field, 'Field')
|
|
2935
|
-
const elem = usingFirstElement(res)
|
|
2936
|
-
const elemId = getElementId(elem)
|
|
3065
|
+
const res = await findFields.call(this, field)
|
|
3066
|
+
assertElementExists(res, field, 'Field')
|
|
3067
|
+
const elem = usingFirstElement(res)
|
|
3068
|
+
const elemId = getElementId(elem)
|
|
2937
3069
|
|
|
2938
3070
|
const proceedMultiple = async (fields) => {
|
|
2939
|
-
const fieldResults = toArray(
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
3071
|
+
const fieldResults = toArray(
|
|
3072
|
+
await forEachAsync(fields, async (el) => {
|
|
3073
|
+
const elementId = getElementId(el)
|
|
3074
|
+
return this.browser.isW3C ? el.getValue() : this.browser.getElementAttribute(elementId, 'value')
|
|
3075
|
+
}),
|
|
3076
|
+
)
|
|
2943
3077
|
|
|
2944
3078
|
if (typeof value === 'boolean') {
|
|
2945
|
-
equals(`no. of items matching > 0: ${field}`)[assertType](value, !!fieldResults.length)
|
|
3079
|
+
equals(`no. of items matching > 0: ${field}`)[assertType](value, !!fieldResults.length)
|
|
2946
3080
|
} else {
|
|
2947
3081
|
// Assert that results were found so the forEach assert does not silently pass
|
|
2948
|
-
equals(`no. of items matching > 0: ${field}`)[assertType](true, !!fieldResults.length)
|
|
2949
|
-
fieldResults.forEach(val => stringIncludes(`fields by ${field}`)[assertType](value, val))
|
|
3082
|
+
equals(`no. of items matching > 0: ${field}`)[assertType](true, !!fieldResults.length)
|
|
3083
|
+
fieldResults.forEach((val) => stringIncludes(`fields by ${field}`)[assertType](value, val))
|
|
2950
3084
|
}
|
|
2951
|
-
}
|
|
3085
|
+
}
|
|
2952
3086
|
|
|
2953
|
-
const proceedSingle = el
|
|
2954
|
-
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
3087
|
+
const proceedSingle = (el) =>
|
|
3088
|
+
el.getValue().then((res) => {
|
|
3089
|
+
if (res === null) {
|
|
3090
|
+
throw new Error(`Element ${el.selector} has no value attribute`)
|
|
3091
|
+
}
|
|
3092
|
+
stringIncludes(`fields by ${field}`)[assertType](value, res)
|
|
3093
|
+
})
|
|
2959
3094
|
|
|
2960
|
-
const filterBySelected = async
|
|
3095
|
+
const filterBySelected = async (elements) =>
|
|
3096
|
+
filterAsync(elements, async (el) => this.browser.isElementSelected(getElementId(el)))
|
|
2961
3097
|
|
|
2962
3098
|
const filterSelectedByValue = async (elements, value) => {
|
|
2963
3099
|
return filterAsync(elements, async (el) => {
|
|
2964
|
-
const elementId = getElementId(el)
|
|
2965
|
-
const currentValue = this.browser.isW3C
|
|
2966
|
-
|
|
2967
|
-
|
|
2968
|
-
|
|
2969
|
-
|
|
2970
|
-
|
|
2971
|
-
|
|
3100
|
+
const elementId = getElementId(el)
|
|
3101
|
+
const currentValue = this.browser.isW3C
|
|
3102
|
+
? await el.getValue()
|
|
3103
|
+
: await this.browser.getElementAttribute(elementId, 'value')
|
|
3104
|
+
const isSelected = await this.browser.isElementSelected(elementId)
|
|
3105
|
+
return currentValue === value && isSelected
|
|
3106
|
+
})
|
|
3107
|
+
}
|
|
3108
|
+
|
|
3109
|
+
const tag = await elem.getTagName()
|
|
2972
3110
|
if (tag === 'select') {
|
|
2973
|
-
const subOptions = await this.browser.findElementsFromElement(elemId, 'css', 'option')
|
|
3111
|
+
const subOptions = await this.browser.findElementsFromElement(elemId, 'css', 'option')
|
|
2974
3112
|
|
|
2975
3113
|
if (value === '') {
|
|
2976
3114
|
// Don't filter by value
|
|
2977
|
-
const selectedOptions = await filterBySelected(subOptions)
|
|
2978
|
-
return proceedMultiple(selectedOptions)
|
|
3115
|
+
const selectedOptions = await filterBySelected(subOptions)
|
|
3116
|
+
return proceedMultiple(selectedOptions)
|
|
2979
3117
|
}
|
|
2980
3118
|
|
|
2981
|
-
const options = await filterSelectedByValue(subOptions, value)
|
|
2982
|
-
return proceedMultiple(options)
|
|
3119
|
+
const options = await filterSelectedByValue(subOptions, value)
|
|
3120
|
+
return proceedMultiple(options)
|
|
2983
3121
|
}
|
|
2984
3122
|
|
|
2985
3123
|
if (tag === 'input') {
|
|
2986
|
-
const fieldType = await elem.getAttribute('type')
|
|
3124
|
+
const fieldType = await elem.getAttribute('type')
|
|
2987
3125
|
|
|
2988
3126
|
if (fieldType === 'checkbox' || fieldType === 'radio') {
|
|
2989
3127
|
if (typeof value === 'boolean') {
|
|
2990
3128
|
// Support boolean values
|
|
2991
|
-
const options = await filterBySelected(res)
|
|
2992
|
-
return proceedMultiple(options)
|
|
3129
|
+
const options = await filterBySelected(res)
|
|
3130
|
+
return proceedMultiple(options)
|
|
2993
3131
|
}
|
|
2994
3132
|
|
|
2995
|
-
const options = await filterSelectedByValue(res, value)
|
|
2996
|
-
return proceedMultiple(options)
|
|
3133
|
+
const options = await filterSelectedByValue(res, value)
|
|
3134
|
+
return proceedMultiple(options)
|
|
2997
3135
|
}
|
|
2998
|
-
return proceedSingle(elem)
|
|
3136
|
+
return proceedSingle(elem)
|
|
2999
3137
|
}
|
|
3000
|
-
return proceedSingle(elem)
|
|
3138
|
+
return proceedSingle(elem)
|
|
3001
3139
|
}
|
|
3002
3140
|
|
|
3003
3141
|
function toArray(item) {
|
|
3004
3142
|
if (!Array.isArray(item)) {
|
|
3005
|
-
return [item]
|
|
3143
|
+
return [item]
|
|
3006
3144
|
}
|
|
3007
|
-
return item
|
|
3145
|
+
return item
|
|
3008
3146
|
}
|
|
3009
3147
|
|
|
3010
3148
|
async function proceedSeeCheckbox(assertType, field) {
|
|
3011
|
-
const res = await findFields.call(this, field)
|
|
3012
|
-
assertElementExists(res, field, 'Field')
|
|
3149
|
+
const res = await findFields.call(this, field)
|
|
3150
|
+
assertElementExists(res, field, 'Field')
|
|
3013
3151
|
|
|
3014
|
-
const selected = await forEachAsync(res, async el => this.browser.isElementSelected(getElementId(el)))
|
|
3015
|
-
return truth(`checkable field "${field}"`, 'to be checked')[assertType](selected)
|
|
3152
|
+
const selected = await forEachAsync(res, async (el) => this.browser.isElementSelected(getElementId(el)))
|
|
3153
|
+
return truth(`checkable field "${field}"`, 'to be checked')[assertType](selected)
|
|
3016
3154
|
}
|
|
3017
3155
|
|
|
3018
3156
|
async function findCheckable(locator, locateFn) {
|
|
3019
|
-
let els
|
|
3020
|
-
locator = new Locator(locator)
|
|
3157
|
+
let els
|
|
3158
|
+
locator = new Locator(locator)
|
|
3021
3159
|
|
|
3022
3160
|
if (this._isCustomLocator(locator)) {
|
|
3023
|
-
return locateFn(locator.value)
|
|
3161
|
+
return locateFn(locator.value)
|
|
3024
3162
|
}
|
|
3025
3163
|
|
|
3026
|
-
if (locator.isAccessibilityId() && !this.isWeb) return locateFn(locator, true)
|
|
3027
|
-
if (!locator.isFuzzy()) return locateFn(locator, true)
|
|
3164
|
+
if (locator.isAccessibilityId() && !this.isWeb) return locateFn(locator, true)
|
|
3165
|
+
if (!locator.isFuzzy()) return locateFn(locator, true)
|
|
3028
3166
|
|
|
3029
|
-
const literal = xpathLocator.literal(locator.value)
|
|
3030
|
-
els = await locateFn(Locator.checkable.byText(literal))
|
|
3031
|
-
if (els.length) return els
|
|
3032
|
-
els = await locateFn(Locator.checkable.byName(literal))
|
|
3033
|
-
if (els.length) return els
|
|
3167
|
+
const literal = xpathLocator.literal(locator.value)
|
|
3168
|
+
els = await locateFn(Locator.checkable.byText(literal))
|
|
3169
|
+
if (els.length) return els
|
|
3170
|
+
els = await locateFn(Locator.checkable.byName(literal))
|
|
3171
|
+
if (els.length) return els
|
|
3034
3172
|
|
|
3035
|
-
return locateFn(locator.value)
|
|
3173
|
+
return locateFn(locator.value) // by css or xpath
|
|
3036
3174
|
}
|
|
3037
3175
|
|
|
3038
3176
|
function withStrictLocator(locator) {
|
|
3039
|
-
locator = new Locator(locator)
|
|
3040
|
-
return locator.simplify()
|
|
3177
|
+
locator = new Locator(locator)
|
|
3178
|
+
return locator.simplify()
|
|
3041
3179
|
}
|
|
3042
3180
|
|
|
3043
3181
|
function isFrameLocator(locator) {
|
|
3044
|
-
locator = new Locator(locator)
|
|
3045
|
-
if (locator.isFrame()) return locator.value
|
|
3046
|
-
return false
|
|
3182
|
+
locator = new Locator(locator)
|
|
3183
|
+
if (locator.isFrame()) return locator.value
|
|
3184
|
+
return false
|
|
3047
3185
|
}
|
|
3048
3186
|
|
|
3049
3187
|
function assertElementExists(res, locator, prefix, suffix) {
|
|
3050
3188
|
if (!res || res.length === 0) {
|
|
3051
|
-
throw new ElementNotFound(locator, prefix, suffix)
|
|
3189
|
+
throw new ElementNotFound(locator, prefix, suffix)
|
|
3052
3190
|
}
|
|
3053
3191
|
}
|
|
3054
3192
|
|
|
3055
3193
|
function usingFirstElement(els) {
|
|
3056
|
-
if (els.length > 1) debug(`[Elements] Using first element out of ${els.length}`)
|
|
3057
|
-
return els[0]
|
|
3194
|
+
if (els.length > 1) debug(`[Elements] Using first element out of ${els.length}`)
|
|
3195
|
+
return els[0]
|
|
3058
3196
|
}
|
|
3059
3197
|
|
|
3060
3198
|
function getElementId(el) {
|
|
3061
3199
|
// W3C WebDriver web element identifier
|
|
3062
3200
|
// https://w3c.github.io/webdriver/#dfn-web-element-identifier
|
|
3063
3201
|
if (el['element-6066-11e4-a52e-4f735466cecf']) {
|
|
3064
|
-
return el['element-6066-11e4-a52e-4f735466cecf']
|
|
3202
|
+
return el['element-6066-11e4-a52e-4f735466cecf']
|
|
3065
3203
|
}
|
|
3066
3204
|
// (deprecated) JsonWireProtocol identifier
|
|
3067
3205
|
// https://github.com/SeleniumHQ/selenium/wiki/JsonWireProtocol#webelement-json-object
|
|
3068
3206
|
if (el.ELEMENT) {
|
|
3069
|
-
return el.ELEMENT
|
|
3207
|
+
return el.ELEMENT
|
|
3070
3208
|
}
|
|
3071
3209
|
|
|
3072
|
-
return null
|
|
3210
|
+
return null
|
|
3073
3211
|
}
|
|
3074
3212
|
|
|
3075
3213
|
// List of known key values to unicode code points
|
|
3076
3214
|
// https://www.w3.org/TR/webdriver/#keyboard-actions
|
|
3077
3215
|
const keyUnicodeMap = {
|
|
3078
3216
|
/* eslint-disable quote-props */
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3082
|
-
|
|
3083
|
-
|
|
3084
|
-
|
|
3085
|
-
|
|
3086
|
-
|
|
3087
|
-
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
|
|
3093
|
-
|
|
3094
|
-
|
|
3095
|
-
|
|
3096
|
-
|
|
3097
|
-
|
|
3098
|
-
|
|
3099
|
-
|
|
3100
|
-
|
|
3217
|
+
Unidentified: '\uE000',
|
|
3218
|
+
Cancel: '\uE001',
|
|
3219
|
+
Clear: '\uE005',
|
|
3220
|
+
Help: '\uE002',
|
|
3221
|
+
Pause: '\uE00B',
|
|
3222
|
+
Backspace: '\uE003',
|
|
3223
|
+
Return: '\uE006',
|
|
3224
|
+
Enter: '\uE007',
|
|
3225
|
+
Escape: '\uE00C',
|
|
3226
|
+
Alt: '\uE00A',
|
|
3227
|
+
AltLeft: '\uE00A',
|
|
3228
|
+
AltRight: '\uE052',
|
|
3229
|
+
Control: '\uE009',
|
|
3230
|
+
ControlLeft: '\uE009',
|
|
3231
|
+
ControlRight: '\uE051',
|
|
3232
|
+
Meta: '\uE03D',
|
|
3233
|
+
MetaLeft: '\uE03D',
|
|
3234
|
+
MetaRight: '\uE053',
|
|
3235
|
+
Shift: '\uE008',
|
|
3236
|
+
ShiftLeft: '\uE008',
|
|
3237
|
+
ShiftRight: '\uE050',
|
|
3238
|
+
Space: '\uE00D',
|
|
3101
3239
|
' ': '\uE00D',
|
|
3102
|
-
|
|
3103
|
-
|
|
3104
|
-
|
|
3105
|
-
|
|
3106
|
-
|
|
3107
|
-
|
|
3108
|
-
|
|
3109
|
-
|
|
3110
|
-
|
|
3111
|
-
|
|
3112
|
-
|
|
3113
|
-
|
|
3114
|
-
|
|
3115
|
-
|
|
3116
|
-
|
|
3117
|
-
|
|
3118
|
-
|
|
3119
|
-
|
|
3120
|
-
|
|
3121
|
-
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3129
|
-
|
|
3130
|
-
|
|
3131
|
-
|
|
3132
|
-
|
|
3133
|
-
|
|
3134
|
-
|
|
3135
|
-
|
|
3136
|
-
|
|
3137
|
-
|
|
3138
|
-
|
|
3139
|
-
|
|
3140
|
-
|
|
3141
|
-
|
|
3142
|
-
|
|
3143
|
-
|
|
3144
|
-
|
|
3145
|
-
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
|
|
3154
|
-
|
|
3155
|
-
|
|
3156
|
-
|
|
3157
|
-
|
|
3158
|
-
|
|
3159
|
-
|
|
3160
|
-
|
|
3161
|
-
|
|
3162
|
-
|
|
3163
|
-
|
|
3164
|
-
|
|
3165
|
-
|
|
3166
|
-
|
|
3167
|
-
|
|
3168
|
-
|
|
3169
|
-
|
|
3170
|
-
|
|
3171
|
-
|
|
3172
|
-
|
|
3173
|
-
|
|
3174
|
-
|
|
3175
|
-
|
|
3176
|
-
|
|
3177
|
-
|
|
3178
|
-
|
|
3179
|
-
|
|
3180
|
-
|
|
3181
|
-
|
|
3182
|
-
|
|
3183
|
-
|
|
3184
|
-
|
|
3185
|
-
|
|
3186
|
-
|
|
3187
|
-
|
|
3188
|
-
|
|
3189
|
-
|
|
3190
|
-
|
|
3191
|
-
|
|
3192
|
-
|
|
3240
|
+
Tab: '\uE004',
|
|
3241
|
+
Insert: '\uE016',
|
|
3242
|
+
Delete: '\uE017',
|
|
3243
|
+
End: '\uE010',
|
|
3244
|
+
Home: '\uE011',
|
|
3245
|
+
PageUp: '\uE00E',
|
|
3246
|
+
PageDown: '\uE00F',
|
|
3247
|
+
ArrowDown: '\uE015',
|
|
3248
|
+
ArrowLeft: '\uE012',
|
|
3249
|
+
ArrowRight: '\uE014',
|
|
3250
|
+
ArrowUp: '\uE013',
|
|
3251
|
+
F1: '\uE031',
|
|
3252
|
+
F2: '\uE032',
|
|
3253
|
+
F3: '\uE033',
|
|
3254
|
+
F4: '\uE034',
|
|
3255
|
+
F5: '\uE035',
|
|
3256
|
+
F6: '\uE036',
|
|
3257
|
+
F7: '\uE037',
|
|
3258
|
+
F8: '\uE038',
|
|
3259
|
+
F9: '\uE039',
|
|
3260
|
+
F10: '\uE03A',
|
|
3261
|
+
F11: '\uE03B',
|
|
3262
|
+
F12: '\uE03C',
|
|
3263
|
+
Numpad0: '\uE01A',
|
|
3264
|
+
Numpad1: '\uE01B',
|
|
3265
|
+
Numpad2: '\uE01C',
|
|
3266
|
+
Numpad3: '\uE01D',
|
|
3267
|
+
Numpad4: '\uE01E',
|
|
3268
|
+
Numpad5: '\uE01F',
|
|
3269
|
+
Numpad6: '\uE020',
|
|
3270
|
+
Numpad7: '\uE021',
|
|
3271
|
+
Numpad8: '\uE022',
|
|
3272
|
+
Numpad9: '\uE023',
|
|
3273
|
+
NumpadMultiply: '\uE024',
|
|
3274
|
+
NumpadAdd: '\uE025',
|
|
3275
|
+
NumpadSubtract: '\uE027',
|
|
3276
|
+
NumpadDecimal: '\uE028',
|
|
3277
|
+
NumpadDivide: '\uE029',
|
|
3278
|
+
NumpadEnter: '\uE007',
|
|
3279
|
+
NumpadInsert: '\uE05C', // 'Numpad0' alternate (when NumLock off)
|
|
3280
|
+
NumpadDelete: '\uE05D', // 'NumpadDecimal' alternate (when NumLock off)
|
|
3281
|
+
NumpadEnd: '\uE056', // 'Numpad1' alternate (when NumLock off)
|
|
3282
|
+
NumpadHome: '\uE057', // 'Numpad7' alternate (when NumLock off)
|
|
3283
|
+
NumpadPageDown: '\uE055', // 'Numpad3' alternate (when NumLock off)
|
|
3284
|
+
NumpadPageUp: '\uE054', // 'Numpad9' alternate (when NumLock off)
|
|
3285
|
+
NumpadArrowDown: '\uE05B', // 'Numpad2' alternate (when NumLock off)
|
|
3286
|
+
NumpadArrowLeft: '\uE058', // 'Numpad4' alternate (when NumLock off)
|
|
3287
|
+
NumpadArrowRight: '\uE05A', // 'Numpad6' alternate (when NumLock off)
|
|
3288
|
+
NumpadArrowUp: '\uE059', // 'Numpad8' alternate (when NumLock off)
|
|
3289
|
+
Comma: '\uE026', // ',' alias
|
|
3290
|
+
Digit0: '0', // '0' alias
|
|
3291
|
+
Digit1: '1', // '1' alias
|
|
3292
|
+
Digit2: '2', // '2' alias
|
|
3293
|
+
Digit3: '3', // '3' alias
|
|
3294
|
+
Digit4: '4', // '4' alias
|
|
3295
|
+
Digit5: '5', // '5' alias
|
|
3296
|
+
Digit6: '6', // '6' alias
|
|
3297
|
+
Digit7: '7', // '7' alias
|
|
3298
|
+
Digit8: '8', // '8' alias
|
|
3299
|
+
Digit9: '9', // '9' alias
|
|
3300
|
+
Equal: '\uE019', // '=' alias
|
|
3301
|
+
KeyA: 'a', // 'a' alias
|
|
3302
|
+
KeyB: 'b', // 'b' alias
|
|
3303
|
+
KeyC: 'c', // 'c' alias
|
|
3304
|
+
KeyD: 'd', // 'd' alias
|
|
3305
|
+
KeyE: 'e', // 'e' alias
|
|
3306
|
+
KeyF: 'f', // 'f' alias
|
|
3307
|
+
KeyG: 'g', // 'g' alias
|
|
3308
|
+
KeyH: 'h', // 'h' alias
|
|
3309
|
+
KeyI: 'i', // 'i' alias
|
|
3310
|
+
KeyJ: 'j', // 'j' alias
|
|
3311
|
+
KeyK: 'k', // 'k' alias
|
|
3312
|
+
KeyL: 'l', // 'l' alias
|
|
3313
|
+
KeyM: 'm', // 'm' alias
|
|
3314
|
+
KeyN: 'n', // 'n' alias
|
|
3315
|
+
KeyO: 'o', // 'o' alias
|
|
3316
|
+
KeyP: 'p', // 'p' alias
|
|
3317
|
+
KeyQ: 'q', // 'q' alias
|
|
3318
|
+
KeyR: 'r', // 'r' alias
|
|
3319
|
+
KeyS: 's', // 's' alias
|
|
3320
|
+
KeyT: 't', // 't' alias
|
|
3321
|
+
KeyU: 'u', // 'u' alias
|
|
3322
|
+
KeyV: 'v', // 'v' alias
|
|
3323
|
+
KeyW: 'w', // 'w' alias
|
|
3324
|
+
KeyX: 'x', // 'x' alias
|
|
3325
|
+
KeyY: 'y', // 'y' alias
|
|
3326
|
+
KeyZ: 'z', // 'z' alias
|
|
3327
|
+
Period: '.', // '.' alias
|
|
3328
|
+
Semicolon: '\uE018', // ';' alias
|
|
3329
|
+
Slash: '/', // '/' alias
|
|
3330
|
+
ZenkakuHankaku: '\uE040',
|
|
3193
3331
|
/* eslint-enable quote-props */
|
|
3194
|
-
}
|
|
3332
|
+
}
|
|
3195
3333
|
|
|
3196
3334
|
function convertKeyToRawKey(key) {
|
|
3197
3335
|
if (Object.prototype.hasOwnProperty.call(keyUnicodeMap, key)) {
|
|
3198
|
-
return keyUnicodeMap[key]
|
|
3336
|
+
return keyUnicodeMap[key]
|
|
3199
3337
|
}
|
|
3200
3338
|
// Key is raw key when no representative unicode code point for value
|
|
3201
|
-
return key
|
|
3339
|
+
return key
|
|
3202
3340
|
}
|
|
3203
3341
|
|
|
3204
3342
|
function getNormalizedKey(key) {
|
|
3205
|
-
let normalizedKey = getNormalizedKeyAttributeValue(key)
|
|
3343
|
+
let normalizedKey = getNormalizedKeyAttributeValue(key)
|
|
3206
3344
|
// Always use "left" modifier keys for non-W3C sessions,
|
|
3207
3345
|
// as JsonWireProtocol does not support "right" modifier keys
|
|
3208
3346
|
if (!this.browser.isW3C) {
|
|
3209
|
-
normalizedKey = normalizedKey.replace(/^(Alt|Control|Meta|Shift)Right$/, '$1')
|
|
3347
|
+
normalizedKey = normalizedKey.replace(/^(Alt|Control|Meta|Shift)Right$/, '$1')
|
|
3210
3348
|
}
|
|
3211
3349
|
if (key !== normalizedKey) {
|
|
3212
|
-
this.debugSection('Input', `Mapping key '${key}' to '${normalizedKey}'`)
|
|
3350
|
+
this.debugSection('Input', `Mapping key '${key}' to '${normalizedKey}'`)
|
|
3213
3351
|
}
|
|
3214
|
-
return convertKeyToRawKey(normalizedKey)
|
|
3352
|
+
return convertKeyToRawKey(normalizedKey)
|
|
3215
3353
|
}
|
|
3216
3354
|
|
|
3217
|
-
const unicodeModifierKeys = modifierKeys.map(k => convertKeyToRawKey(k))
|
|
3355
|
+
const unicodeModifierKeys = modifierKeys.map((k) => convertKeyToRawKey(k))
|
|
3218
3356
|
function isModifierKey(key) {
|
|
3219
|
-
return unicodeModifierKeys.includes(key)
|
|
3357
|
+
return unicodeModifierKeys.includes(key)
|
|
3220
3358
|
}
|
|
3221
3359
|
|
|
3222
3360
|
function highlightActiveElement(element) {
|
|
3223
3361
|
if (this.options.highlightElement && global.debugMode) {
|
|
3224
|
-
highlightElement(element, this.browser)
|
|
3362
|
+
highlightElement(element, this.browser)
|
|
3225
3363
|
}
|
|
3226
3364
|
}
|
|
3227
3365
|
|
|
3228
3366
|
function prepareLocateFn(context) {
|
|
3229
|
-
if (!context) return this._locate.bind(this)
|
|
3367
|
+
if (!context) return this._locate.bind(this)
|
|
3230
3368
|
return (l) => {
|
|
3231
|
-
l = new Locator(l, 'css')
|
|
3369
|
+
l = new Locator(l, 'css')
|
|
3232
3370
|
return this._locate(context, true).then(async (res) => {
|
|
3233
|
-
assertElementExists(res, context, 'Context element')
|
|
3371
|
+
assertElementExists(res, context, 'Context element')
|
|
3234
3372
|
if (l.react) {
|
|
3235
|
-
return res[0].react$$(l.react, l.props || undefined)
|
|
3373
|
+
return res[0].react$$(l.react, l.props || undefined)
|
|
3236
3374
|
}
|
|
3237
|
-
return res[0].$$(l.simplify())
|
|
3238
|
-
})
|
|
3239
|
-
}
|
|
3375
|
+
return res[0].$$(l.simplify())
|
|
3376
|
+
})
|
|
3377
|
+
}
|
|
3240
3378
|
}
|
|
3241
3379
|
|
|
3242
|
-
module.exports = WebDriver
|
|
3380
|
+
module.exports = WebDriver
|