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