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