codeceptjs 3.5.0 → 3.5.1-2.beta.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +24 -25
- package/lib/actor.js +6 -3
- package/lib/ai.js +12 -3
- package/lib/cli.js +12 -2
- package/lib/codecept.js +4 -0
- package/lib/colorUtils.js +10 -0
- package/lib/command/definitions.js +2 -7
- package/lib/command/dryRun.js +2 -1
- package/lib/command/info.js +24 -0
- package/lib/command/init.js +51 -5
- package/lib/command/run-multiple/collection.js +17 -5
- package/lib/command/run-multiple.js +4 -2
- package/lib/command/run-workers.js +66 -4
- package/lib/command/run.js +7 -0
- package/lib/command/workers/runTests.js +39 -0
- package/lib/data/context.js +14 -6
- package/lib/event.js +4 -0
- package/lib/helper/ApiDataFactory.js +2 -1
- package/lib/helper/Appium.js +73 -24
- package/lib/helper/Expect.js +422 -0
- package/lib/helper/FileSystem.js +1 -1
- package/lib/helper/GraphQL.js +25 -0
- package/lib/helper/Nightmare.js +9 -4
- package/lib/helper/OpenAI.js +14 -10
- package/lib/helper/Playwright.js +1205 -288
- package/lib/helper/Protractor.js +11 -6
- package/lib/helper/Puppeteer.js +173 -61
- package/lib/helper/TestCafe.js +44 -9
- package/lib/helper/WebDriver.js +231 -82
- package/lib/helper/errors/ElementNotFound.js +2 -1
- package/lib/helper/extras/PlaywrightReactVueLocator.js +38 -0
- package/lib/helper/scripts/blurElement.js +17 -0
- package/lib/helper/scripts/focusElement.js +17 -0
- package/lib/helper/scripts/highlightElement.js +2 -2
- package/lib/html.js +3 -3
- package/lib/interfaces/bdd.js +1 -1
- package/lib/interfaces/gherkin.js +37 -3
- package/lib/interfaces/scenarioConfig.js +1 -0
- package/lib/locator.js +17 -4
- package/lib/mochaFactory.js +2 -1
- package/lib/output.js +1 -1
- package/lib/pause.js +12 -9
- package/lib/plugin/autoLogin.js +45 -10
- package/lib/plugin/heal.js +47 -17
- package/lib/plugin/retryFailedStep.js +10 -1
- package/lib/plugin/retryTo.js +2 -4
- package/lib/plugin/selenoid.js +6 -1
- package/lib/plugin/standardActingHelpers.js +0 -2
- package/lib/plugin/stepByStepReport.js +2 -2
- package/lib/plugin/tryTo.js +5 -7
- package/lib/plugin/wdio.js +0 -1
- package/lib/recorder.js +20 -9
- package/lib/session.js +1 -1
- package/lib/step.js +30 -11
- package/lib/ui.js +1 -0
- package/lib/utils.js +18 -1
- package/lib/workers.js +28 -3
- package/package.json +108 -98
- package/translations/de-DE.js +5 -0
- package/translations/fr-FR.js +14 -1
- package/translations/it-IT.js +1 -0
- package/translations/ja-JP.js +5 -0
- package/translations/pl-PL.js +5 -0
- package/translations/pt-BR.js +1 -0
- package/translations/ru-RU.js +1 -0
- package/translations/zh-CN.js +5 -0
- package/translations/zh-TW.js +5 -0
- package/typings/index.d.ts +8 -6
- package/typings/promiseBasedTypes.d.ts +784 -822
- package/typings/types.d.ts +1214 -727
- package/CHANGELOG.md +0 -2492
- package/docs/advanced.md +0 -351
- package/docs/ai.md +0 -246
- package/docs/api.md +0 -323
- package/docs/basics.md +0 -980
- package/docs/bdd.md +0 -535
- package/docs/best.md +0 -237
- package/docs/books.md +0 -37
- package/docs/bootstrap.md +0 -135
- package/docs/build/ApiDataFactory.js +0 -409
- package/docs/build/Appium.js +0 -1978
- package/docs/build/FileSystem.js +0 -228
- package/docs/build/GraphQL.js +0 -204
- package/docs/build/GraphQLDataFactory.js +0 -309
- package/docs/build/JSONResponse.js +0 -338
- package/docs/build/Mochawesome.js +0 -71
- package/docs/build/Nightmare.js +0 -2147
- package/docs/build/OpenAI.js +0 -122
- package/docs/build/Playwright.js +0 -4134
- package/docs/build/Polly.js +0 -42
- package/docs/build/Protractor.js +0 -2701
- package/docs/build/Puppeteer.js +0 -3743
- package/docs/build/REST.js +0 -344
- package/docs/build/SeleniumWebdriver.js +0 -76
- package/docs/build/TestCafe.js +0 -2059
- package/docs/build/WebDriver.js +0 -4042
- package/docs/changelog.md +0 -2501
- package/docs/commands.md +0 -254
- package/docs/community-helpers.md +0 -58
- package/docs/configuration.md +0 -157
- package/docs/continuous-integration.md +0 -22
- package/docs/custom-helpers.md +0 -306
- package/docs/data.md +0 -375
- package/docs/detox.md +0 -235
- package/docs/docker.md +0 -137
- package/docs/email.md +0 -183
- package/docs/examples.md +0 -149
- package/docs/helpers/ApiDataFactory.md +0 -266
- package/docs/helpers/Appium.md +0 -1317
- package/docs/helpers/Detox.md +0 -586
- package/docs/helpers/FileSystem.md +0 -152
- package/docs/helpers/GraphQL.md +0 -130
- package/docs/helpers/GraphQLDataFactory.md +0 -226
- package/docs/helpers/JSONResponse.md +0 -254
- package/docs/helpers/Mochawesome.md +0 -8
- package/docs/helpers/MockRequest.md +0 -377
- package/docs/helpers/Nightmare.md +0 -1258
- package/docs/helpers/OpenAI.md +0 -70
- package/docs/helpers/Playwright.md +0 -2250
- package/docs/helpers/Polly.md +0 -44
- package/docs/helpers/Puppeteer-firefox.md +0 -86
- package/docs/helpers/Puppeteer.md +0 -2147
- package/docs/helpers/REST.md +0 -218
- package/docs/helpers/TestCafe.md +0 -1224
- package/docs/helpers/WebDriver.md +0 -2325
- package/docs/hooks.md +0 -340
- package/docs/index.md +0 -111
- package/docs/installation.md +0 -75
- package/docs/internal-api.md +0 -265
- package/docs/locators.md +0 -331
- package/docs/mobile-react-native-locators.md +0 -67
- package/docs/mobile.md +0 -344
- package/docs/nightmare.md +0 -223
- package/docs/pageobjects.md +0 -291
- package/docs/parallel.md +0 -288
- package/docs/playwright.md +0 -609
- package/docs/plugins.md +0 -1225
- package/docs/puppeteer.md +0 -316
- package/docs/quickstart.md +0 -163
- package/docs/react.md +0 -69
- package/docs/reports.md +0 -392
- package/docs/secrets.md +0 -36
- package/docs/shadow.md +0 -68
- package/docs/shared/keys.mustache +0 -31
- package/docs/shared/react.mustache +0 -1
- package/docs/testcafe.md +0 -174
- package/docs/translation.md +0 -247
- package/docs/tutorial.md +0 -271
- package/docs/typescript.md +0 -180
- package/docs/ui.md +0 -59
- package/docs/videos.md +0 -28
- package/docs/visual.md +0 -202
- package/docs/vue.md +0 -121
- package/docs/webapi/amOnPage.mustache +0 -11
- package/docs/webapi/appendField.mustache +0 -11
- package/docs/webapi/attachFile.mustache +0 -12
- package/docs/webapi/checkOption.mustache +0 -13
- package/docs/webapi/clearCookie.mustache +0 -10
- package/docs/webapi/clearField.mustache +0 -9
- package/docs/webapi/click.mustache +0 -25
- package/docs/webapi/clickLink.mustache +0 -8
- package/docs/webapi/closeCurrentTab.mustache +0 -7
- package/docs/webapi/closeOtherTabs.mustache +0 -8
- package/docs/webapi/dontSee.mustache +0 -11
- package/docs/webapi/dontSeeCheckboxIsChecked.mustache +0 -10
- package/docs/webapi/dontSeeCookie.mustache +0 -8
- package/docs/webapi/dontSeeCurrentUrlEquals.mustache +0 -10
- package/docs/webapi/dontSeeElement.mustache +0 -8
- package/docs/webapi/dontSeeElementInDOM.mustache +0 -8
- package/docs/webapi/dontSeeInCurrentUrl.mustache +0 -4
- package/docs/webapi/dontSeeInField.mustache +0 -11
- package/docs/webapi/dontSeeInSource.mustache +0 -8
- package/docs/webapi/dontSeeInTitle.mustache +0 -8
- package/docs/webapi/doubleClick.mustache +0 -13
- package/docs/webapi/downloadFile.mustache +0 -12
- package/docs/webapi/dragAndDrop.mustache +0 -9
- package/docs/webapi/dragSlider.mustache +0 -11
- package/docs/webapi/executeAsyncScript.mustache +0 -24
- package/docs/webapi/executeScript.mustache +0 -26
- package/docs/webapi/fillField.mustache +0 -16
- package/docs/webapi/forceClick.mustache +0 -28
- package/docs/webapi/forceRightClick.mustache +0 -18
- package/docs/webapi/grabAllWindowHandles.mustache +0 -7
- package/docs/webapi/grabAttributeFrom.mustache +0 -10
- package/docs/webapi/grabAttributeFromAll.mustache +0 -9
- package/docs/webapi/grabBrowserLogs.mustache +0 -9
- package/docs/webapi/grabCookie.mustache +0 -11
- package/docs/webapi/grabCssPropertyFrom.mustache +0 -11
- package/docs/webapi/grabCssPropertyFromAll.mustache +0 -10
- package/docs/webapi/grabCurrentUrl.mustache +0 -9
- package/docs/webapi/grabCurrentWindowHandle.mustache +0 -6
- package/docs/webapi/grabDataFromPerformanceTiming.mustache +0 -20
- package/docs/webapi/grabElementBoundingRect.mustache +0 -20
- package/docs/webapi/grabGeoLocation.mustache +0 -8
- package/docs/webapi/grabHTMLFrom.mustache +0 -10
- package/docs/webapi/grabHTMLFromAll.mustache +0 -9
- package/docs/webapi/grabNumberOfOpenTabs.mustache +0 -8
- package/docs/webapi/grabNumberOfVisibleElements.mustache +0 -9
- package/docs/webapi/grabPageScrollPosition.mustache +0 -8
- package/docs/webapi/grabPopupText.mustache +0 -5
- package/docs/webapi/grabSource.mustache +0 -8
- package/docs/webapi/grabTextFrom.mustache +0 -10
- package/docs/webapi/grabTextFromAll.mustache +0 -9
- package/docs/webapi/grabTitle.mustache +0 -8
- package/docs/webapi/grabValueFrom.mustache +0 -9
- package/docs/webapi/grabValueFromAll.mustache +0 -8
- package/docs/webapi/moveCursorTo.mustache +0 -12
- package/docs/webapi/openNewTab.mustache +0 -7
- package/docs/webapi/pressKey.mustache +0 -12
- package/docs/webapi/pressKeyDown.mustache +0 -12
- package/docs/webapi/pressKeyUp.mustache +0 -12
- package/docs/webapi/pressKeyWithKeyNormalization.mustache +0 -60
- package/docs/webapi/refreshPage.mustache +0 -6
- package/docs/webapi/resizeWindow.mustache +0 -6
- package/docs/webapi/rightClick.mustache +0 -14
- package/docs/webapi/saveElementScreenshot.mustache +0 -10
- package/docs/webapi/saveScreenshot.mustache +0 -12
- package/docs/webapi/say.mustache +0 -10
- package/docs/webapi/scrollIntoView.mustache +0 -11
- package/docs/webapi/scrollPageToBottom.mustache +0 -6
- package/docs/webapi/scrollPageToTop.mustache +0 -6
- package/docs/webapi/scrollTo.mustache +0 -12
- package/docs/webapi/see.mustache +0 -11
- package/docs/webapi/seeAttributesOnElements.mustache +0 -9
- package/docs/webapi/seeCheckboxIsChecked.mustache +0 -10
- package/docs/webapi/seeCookie.mustache +0 -8
- package/docs/webapi/seeCssPropertiesOnElements.mustache +0 -9
- package/docs/webapi/seeCurrentUrlEquals.mustache +0 -11
- package/docs/webapi/seeElement.mustache +0 -8
- package/docs/webapi/seeElementInDOM.mustache +0 -8
- package/docs/webapi/seeInCurrentUrl.mustache +0 -8
- package/docs/webapi/seeInField.mustache +0 -12
- package/docs/webapi/seeInPopup.mustache +0 -8
- package/docs/webapi/seeInSource.mustache +0 -7
- package/docs/webapi/seeInTitle.mustache +0 -8
- package/docs/webapi/seeNumberOfElements.mustache +0 -11
- package/docs/webapi/seeNumberOfVisibleElements.mustache +0 -10
- package/docs/webapi/seeTextEquals.mustache +0 -9
- package/docs/webapi/seeTitleEquals.mustache +0 -8
- package/docs/webapi/selectOption.mustache +0 -21
- package/docs/webapi/setCookie.mustache +0 -16
- package/docs/webapi/setGeoLocation.mustache +0 -12
- package/docs/webapi/switchTo.mustache +0 -9
- package/docs/webapi/switchToNextTab.mustache +0 -10
- package/docs/webapi/switchToPreviousTab.mustache +0 -10
- package/docs/webapi/type.mustache +0 -21
- package/docs/webapi/uncheckOption.mustache +0 -13
- package/docs/webapi/wait.mustache +0 -8
- package/docs/webapi/waitForClickable.mustache +0 -11
- package/docs/webapi/waitForDetached.mustache +0 -10
- package/docs/webapi/waitForElement.mustache +0 -11
- package/docs/webapi/waitForEnabled.mustache +0 -6
- package/docs/webapi/waitForFunction.mustache +0 -17
- package/docs/webapi/waitForInvisible.mustache +0 -10
- package/docs/webapi/waitForText.mustache +0 -13
- package/docs/webapi/waitForValue.mustache +0 -10
- package/docs/webapi/waitForVisible.mustache +0 -10
- package/docs/webapi/waitInUrl.mustache +0 -9
- package/docs/webapi/waitNumberOfVisibleElements.mustache +0 -10
- package/docs/webapi/waitToHide.mustache +0 -10
- package/docs/webapi/waitUrlEquals.mustache +0 -10
- package/docs/webdriver.md +0 -657
- package/docs/wiki/Books-&-Posts.md +0 -27
- package/docs/wiki/Community-Helpers-&-Plugins.md +0 -49
- package/docs/wiki/Converting-Playwright-to-Istanbul-Coverage.md +0 -29
- package/docs/wiki/Examples.md +0 -139
- package/docs/wiki/Google-Summer-of-Code-(GSoC)-2020.md +0 -68
- package/docs/wiki/Home.md +0 -16
- package/docs/wiki/Release-Process.md +0 -24
- package/docs/wiki/Roadmap.md +0 -23
- package/docs/wiki/Tests.md +0 -1393
- package/docs/wiki/Upgrading-to-CodeceptJS-3.md +0 -153
- package/docs/wiki/Videos.md +0 -19
package/lib/helper/WebDriver.js
CHANGED
|
@@ -30,6 +30,8 @@ const ConnectionRefused = require('./errors/ConnectionRefused');
|
|
|
30
30
|
const Locator = require('../locator');
|
|
31
31
|
const { highlightElement } = require('./scripts/highlightElement');
|
|
32
32
|
const store = require('../store');
|
|
33
|
+
const { focusElement } = require('./scripts/focusElement');
|
|
34
|
+
const { blurElement } = require('./scripts/blurElement');
|
|
33
35
|
|
|
34
36
|
const SHADOW = 'shadow';
|
|
35
37
|
const webRoot = 'body';
|
|
@@ -60,7 +62,9 @@ const webRoot = 'body';
|
|
|
60
62
|
* @prop {object} [desiredCapabilities] Selenium's [desired capabilities](https://github.com/SeleniumHQ/selenium/wiki/DesiredCapabilities).
|
|
61
63
|
* @prop {boolean} [manualStart=false] - do not start browser before a test, start it manually inside a helper with `this.helpers["WebDriver"]._startBrowser()`.
|
|
62
64
|
* @prop {object} [timeouts] [WebDriver timeouts](http://webdriver.io/docs/timeouts.html) defined as hash.
|
|
63
|
-
* @prop {boolean} [highlightElement] - highlight the interacting elements
|
|
65
|
+
* @prop {boolean} [highlightElement] - highlight the interacting elements. Default: false. Note: only activate under verbose mode (--verbose).
|
|
66
|
+
* @prop {string} [logLevel=silent] - level of logging verbosity. Default: silent. Options: trace | debug | info | warn | error | silent. More info: https://webdriver.io/docs/configuration/#loglevel
|
|
67
|
+
* @prop {boolean} [devtoolsProtocol=false] - enable devtools protocol. Default: false. More info: https://webdriver.io/docs/automationProtocols/#devtools-protocol.
|
|
64
68
|
*/
|
|
65
69
|
const config = {};
|
|
66
70
|
|
|
@@ -70,6 +74,13 @@ const config = {};
|
|
|
70
74
|
*
|
|
71
75
|
* WebDriver requires Selenium Server and ChromeDriver/GeckoDriver to be installed. Those tools can be easily installed via NPM. Please check [Testing with WebDriver](https://codecept.io/webdriver/#testing-with-webdriver) for more details.
|
|
72
76
|
*
|
|
77
|
+
* With the release of WebdriverIO version v8.14.0, and onwards, all driver management hassles are now a thing of the past 🙌. Read more [here](https://webdriver.io/blog/2023/07/31/driver-management/).
|
|
78
|
+
* One of the significant advantages of this update is that you can now get rid of any driver services you previously had to manage, such as
|
|
79
|
+
* `wdio-chromedriver-service`, `wdio-geckodriver-service`, `wdio-edgedriver-service`, `wdio-safaridriver-service`, and even `@wdio/selenium-standalone-service`.
|
|
80
|
+
*
|
|
81
|
+
* For those who require custom driver options, fear not; WebDriver Helper allows you to pass in driver options through custom WebDriver configuration.
|
|
82
|
+
* If you have a custom grid, use a cloud service, or prefer to run your own driver, there's no need to worry since WebDriver Helper will only start a driver when there are no other connection information settings like hostname or port specified.
|
|
83
|
+
*
|
|
73
84
|
* <!-- configuration -->
|
|
74
85
|
*
|
|
75
86
|
* Example:
|
|
@@ -91,6 +102,28 @@ const config = {};
|
|
|
91
102
|
* }
|
|
92
103
|
* ```
|
|
93
104
|
*
|
|
105
|
+
* Testing Chrome locally is now more convenient than ever. You can define a browser channel, and WebDriver Helper will take care of downloading the specified browser version for you.
|
|
106
|
+
* For example:
|
|
107
|
+
*
|
|
108
|
+
* ```js
|
|
109
|
+
* {
|
|
110
|
+
* helpers: {
|
|
111
|
+
* WebDriver : {
|
|
112
|
+
* smartWait: 5000,
|
|
113
|
+
* browser: "chrome",
|
|
114
|
+
* browserVersion: '116.0.5793.0', // or 'stable', 'beta', 'dev' or 'canary'
|
|
115
|
+
* restart: false,
|
|
116
|
+
* windowSize: "maximize",
|
|
117
|
+
* timeouts: {
|
|
118
|
+
* "script": 60000,
|
|
119
|
+
* "page load": 10000
|
|
120
|
+
* }
|
|
121
|
+
* }
|
|
122
|
+
* }
|
|
123
|
+
* }
|
|
124
|
+
* ```
|
|
125
|
+
*
|
|
126
|
+
*
|
|
94
127
|
* Example with basic authentication
|
|
95
128
|
* ```js
|
|
96
129
|
* {
|
|
@@ -131,6 +164,25 @@ const config = {};
|
|
|
131
164
|
* }
|
|
132
165
|
* ```
|
|
133
166
|
*
|
|
167
|
+
* ### Running with devtools protocol
|
|
168
|
+
*
|
|
169
|
+
* ```js
|
|
170
|
+
* {
|
|
171
|
+
* helpers: {
|
|
172
|
+
* WebDriver : {
|
|
173
|
+
* url: "http://localhost",
|
|
174
|
+
* browser: "chrome",
|
|
175
|
+
* devtoolsProtocol: true,
|
|
176
|
+
* desiredCapabilities: {
|
|
177
|
+
* chromeOptions: {
|
|
178
|
+
* args: [ "--headless", "--disable-gpu", "--no-sandbox" ]
|
|
179
|
+
* }
|
|
180
|
+
* }
|
|
181
|
+
* }
|
|
182
|
+
* }
|
|
183
|
+
* }
|
|
184
|
+
* ```
|
|
185
|
+
*
|
|
134
186
|
* ### Internet Explorer
|
|
135
187
|
*
|
|
136
188
|
* Additional configuration params can be used from [IE options](https://seleniumhq.github.io/selenium/docs/api/rb/Selenium/WebDriver/IE/Options.html)
|
|
@@ -413,7 +465,6 @@ class WebDriver extends Helper {
|
|
|
413
465
|
_validateConfig(config) {
|
|
414
466
|
const defaults = {
|
|
415
467
|
logLevel: 'silent',
|
|
416
|
-
path: '/wd/hub',
|
|
417
468
|
// codeceptjs
|
|
418
469
|
remoteFileUpload: true,
|
|
419
470
|
smartWait: 0,
|
|
@@ -427,17 +478,23 @@ class WebDriver extends Helper {
|
|
|
427
478
|
keepCookies: false,
|
|
428
479
|
keepBrowserState: false,
|
|
429
480
|
deprecationWarnings: false,
|
|
481
|
+
highlightElement: false,
|
|
430
482
|
};
|
|
431
483
|
|
|
432
484
|
// override defaults with config
|
|
433
485
|
config = Object.assign(defaults, config);
|
|
434
486
|
|
|
435
|
-
if (
|
|
487
|
+
if (config.host) {
|
|
488
|
+
// webdriverio spec
|
|
489
|
+
config.hostname = config.host;
|
|
490
|
+
config.path = '/wd/hub';
|
|
491
|
+
}
|
|
436
492
|
config.baseUrl = config.url || config.baseUrl;
|
|
437
493
|
if (config.desiredCapabilities && Object.keys(config.desiredCapabilities).length) {
|
|
438
494
|
config.capabilities = config.desiredCapabilities;
|
|
439
495
|
}
|
|
440
496
|
config.capabilities.browserName = config.browser || config.capabilities.browserName;
|
|
497
|
+
config.capabilities.browserVersion = config.browserVersion || config.capabilities.browserVersion;
|
|
441
498
|
if (config.capabilities.chromeOptions) {
|
|
442
499
|
config.capabilities['goog:chromeOptions'] = config.capabilities.chromeOptions;
|
|
443
500
|
delete config.capabilities.chromeOptions;
|
|
@@ -539,6 +596,10 @@ class WebDriver extends Helper {
|
|
|
539
596
|
delete this.options.capabilities.hostname;
|
|
540
597
|
delete this.options.capabilities.port;
|
|
541
598
|
delete this.options.capabilities.path;
|
|
599
|
+
if (this.options.devtoolsProtocol) {
|
|
600
|
+
if (!['chrome', 'chromium'].includes(this.options.browser.toLowerCase())) throw Error('The devtools protocol is only working with Chrome or Chromium');
|
|
601
|
+
this.options.automationProtocol = 'devtools';
|
|
602
|
+
}
|
|
542
603
|
this.browser = await webdriverio.remote(this.options);
|
|
543
604
|
}
|
|
544
605
|
} catch (err) {
|
|
@@ -866,6 +927,14 @@ class WebDriver extends Helper {
|
|
|
866
927
|
return findFields.call(this, locator).then(res => res);
|
|
867
928
|
}
|
|
868
929
|
|
|
930
|
+
/**
|
|
931
|
+
* {{> grabWebElements }}
|
|
932
|
+
*
|
|
933
|
+
*/
|
|
934
|
+
async grabWebElements(locator) {
|
|
935
|
+
return this._locate(locator);
|
|
936
|
+
}
|
|
937
|
+
|
|
869
938
|
/**
|
|
870
939
|
* Set [WebDriver timeouts](https://webdriver.io/docs/timeouts.html) in realtime.
|
|
871
940
|
*
|
|
@@ -1032,7 +1101,8 @@ class WebDriver extends Helper {
|
|
|
1032
1101
|
assertElementExists(res, field, 'Field');
|
|
1033
1102
|
const elem = usingFirstElement(res);
|
|
1034
1103
|
highlightActiveElement.call(this, elem);
|
|
1035
|
-
|
|
1104
|
+
await elem.clearValue();
|
|
1105
|
+
await elem.setValue(value.toString());
|
|
1036
1106
|
}
|
|
1037
1107
|
|
|
1038
1108
|
/**
|
|
@@ -1044,6 +1114,10 @@ class WebDriver extends Helper {
|
|
|
1044
1114
|
assertElementExists(res, field, 'Field');
|
|
1045
1115
|
const elem = usingFirstElement(res);
|
|
1046
1116
|
highlightActiveElement.call(this, elem);
|
|
1117
|
+
if (this.options.automationProtocol) {
|
|
1118
|
+
const curentValue = await elem.getValue();
|
|
1119
|
+
return elem.setValue(curentValue + value.toString());
|
|
1120
|
+
}
|
|
1047
1121
|
return elem.addValue(value.toString());
|
|
1048
1122
|
}
|
|
1049
1123
|
|
|
@@ -1056,6 +1130,9 @@ class WebDriver extends Helper {
|
|
|
1056
1130
|
assertElementExists(res, field, 'Field');
|
|
1057
1131
|
const elem = usingFirstElement(res);
|
|
1058
1132
|
highlightActiveElement.call(this, elem);
|
|
1133
|
+
if (this.options.automationProtocol) {
|
|
1134
|
+
return elem.setValue('');
|
|
1135
|
+
}
|
|
1059
1136
|
return elem.clearValue(getElementId(elem));
|
|
1060
1137
|
}
|
|
1061
1138
|
|
|
@@ -1093,8 +1170,9 @@ class WebDriver extends Helper {
|
|
|
1093
1170
|
}
|
|
1094
1171
|
|
|
1095
1172
|
/**
|
|
1096
|
-
* {{> attachFile }}
|
|
1097
1173
|
* Appium: not tested
|
|
1174
|
+
*
|
|
1175
|
+
* {{> attachFile }}
|
|
1098
1176
|
*/
|
|
1099
1177
|
async attachFile(locator, pathToFile) {
|
|
1100
1178
|
let file = path.join(global.codecept_dir, pathToFile);
|
|
@@ -1108,7 +1186,7 @@ class WebDriver extends Helper {
|
|
|
1108
1186
|
const el = usingFirstElement(res);
|
|
1109
1187
|
|
|
1110
1188
|
// Remote Upload (when running Selenium Server)
|
|
1111
|
-
if (this.options.remoteFileUpload) {
|
|
1189
|
+
if (this.options.remoteFileUpload && !this.options.automationProtocol) {
|
|
1112
1190
|
try {
|
|
1113
1191
|
this.debugSection('File', 'Uploading file to remote server');
|
|
1114
1192
|
file = await this.browser.uploadFile(file);
|
|
@@ -1121,8 +1199,8 @@ class WebDriver extends Helper {
|
|
|
1121
1199
|
}
|
|
1122
1200
|
|
|
1123
1201
|
/**
|
|
1124
|
-
* {{> checkOption }}
|
|
1125
1202
|
* Appium: not tested
|
|
1203
|
+
* {{> checkOption }}
|
|
1126
1204
|
*/
|
|
1127
1205
|
async checkOption(field, context = null) {
|
|
1128
1206
|
const clickMethod = this.browser.isMobile && !this.browser.isW3C ? 'touchClick' : 'elementClick';
|
|
@@ -1141,8 +1219,8 @@ class WebDriver extends Helper {
|
|
|
1141
1219
|
}
|
|
1142
1220
|
|
|
1143
1221
|
/**
|
|
1144
|
-
* {{> uncheckOption }}
|
|
1145
1222
|
* Appium: not tested
|
|
1223
|
+
* {{> uncheckOption }}
|
|
1146
1224
|
*/
|
|
1147
1225
|
async uncheckOption(field, context = null) {
|
|
1148
1226
|
const clickMethod = this.browser.isMobile && !this.browser.isW3C ? 'touchClick' : 'elementClick';
|
|
@@ -1345,7 +1423,8 @@ class WebDriver extends Helper {
|
|
|
1345
1423
|
*
|
|
1346
1424
|
*/
|
|
1347
1425
|
async seeInField(field, value) {
|
|
1348
|
-
|
|
1426
|
+
const _value = (typeof value === 'boolean') ? value : value.toString();
|
|
1427
|
+
return proceedSeeField.call(this, 'assert', field, _value);
|
|
1349
1428
|
}
|
|
1350
1429
|
|
|
1351
1430
|
/**
|
|
@@ -1353,20 +1432,21 @@ class WebDriver extends Helper {
|
|
|
1353
1432
|
*
|
|
1354
1433
|
*/
|
|
1355
1434
|
async dontSeeInField(field, value) {
|
|
1356
|
-
|
|
1435
|
+
const _value = (typeof value === 'boolean') ? value : value.toString();
|
|
1436
|
+
return proceedSeeField.call(this, 'negate', field, _value);
|
|
1357
1437
|
}
|
|
1358
1438
|
|
|
1359
1439
|
/**
|
|
1360
|
-
* {{> seeCheckboxIsChecked }}
|
|
1361
1440
|
* Appium: not tested
|
|
1441
|
+
* {{> seeCheckboxIsChecked }}
|
|
1362
1442
|
*/
|
|
1363
1443
|
async seeCheckboxIsChecked(field) {
|
|
1364
1444
|
return proceedSeeCheckbox.call(this, 'assert', field);
|
|
1365
1445
|
}
|
|
1366
1446
|
|
|
1367
1447
|
/**
|
|
1368
|
-
* {{> dontSeeCheckboxIsChecked }}
|
|
1369
1448
|
* Appium: not tested
|
|
1449
|
+
* {{> dontSeeCheckboxIsChecked }}
|
|
1370
1450
|
*/
|
|
1371
1451
|
async dontSeeCheckboxIsChecked(field) {
|
|
1372
1452
|
return proceedSeeCheckbox.call(this, 'negate', field);
|
|
@@ -1484,33 +1564,33 @@ class WebDriver extends Helper {
|
|
|
1484
1564
|
async seeCssPropertiesOnElements(locator, cssProperties) {
|
|
1485
1565
|
const res = await this._locate(locator);
|
|
1486
1566
|
assertElementExists(res, locator);
|
|
1567
|
+
|
|
1568
|
+
const cssPropertiesCamelCase = convertCssPropertiesToCamelCase(cssProperties);
|
|
1487
1569
|
const elemAmount = res.length;
|
|
1570
|
+
let props = [];
|
|
1488
1571
|
|
|
1489
|
-
|
|
1490
|
-
|
|
1491
|
-
const
|
|
1492
|
-
if (isColorProperty(prop)
|
|
1493
|
-
|
|
1572
|
+
for (const element of res) {
|
|
1573
|
+
for (const prop of Object.keys(cssProperties)) {
|
|
1574
|
+
const cssProp = await this.grabCssPropertyFrom(locator, prop);
|
|
1575
|
+
if (isColorProperty(prop)) {
|
|
1576
|
+
props.push(convertColorToRGBA(cssProp));
|
|
1577
|
+
} else {
|
|
1578
|
+
props.push(cssProp);
|
|
1494
1579
|
}
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
});
|
|
1498
|
-
|
|
1499
|
-
const cssPropertiesCamelCase = convertCssPropertiesToCamelCase(cssProperties);
|
|
1580
|
+
}
|
|
1581
|
+
}
|
|
1500
1582
|
|
|
1501
1583
|
const values = Object.keys(cssPropertiesCamelCase).map(key => cssPropertiesCamelCase[key]);
|
|
1502
1584
|
if (!Array.isArray(props)) props = [props];
|
|
1503
1585
|
let chunked = chunkArray(props, values.length);
|
|
1504
1586
|
chunked = chunked.filter((val) => {
|
|
1505
1587
|
for (let i = 0; i < val.length; ++i) {
|
|
1506
|
-
|
|
1588
|
+
// eslint-disable-next-line eqeqeq
|
|
1589
|
+
if (val[i] != values[i]) return false;
|
|
1507
1590
|
}
|
|
1508
1591
|
return true;
|
|
1509
1592
|
});
|
|
1510
|
-
return assert.
|
|
1511
|
-
chunked.length === elemAmount,
|
|
1512
|
-
`expected all elements (${(new Locator(locator))}) to have CSS property ${JSON.stringify(cssProperties)}`,
|
|
1513
|
-
);
|
|
1593
|
+
return equals(`all elements (${(new Locator(locator))}) to have CSS property ${JSON.stringify(cssProperties)}`).assert(chunked.length, elemAmount);
|
|
1514
1594
|
}
|
|
1515
1595
|
|
|
1516
1596
|
/**
|
|
@@ -1530,7 +1610,9 @@ class WebDriver extends Helper {
|
|
|
1530
1610
|
let chunked = chunkArray(attrs, values.length);
|
|
1531
1611
|
chunked = chunked.filter((val) => {
|
|
1532
1612
|
for (let i = 0; i < val.length; ++i) {
|
|
1533
|
-
|
|
1613
|
+
const _actual = Number.isNaN(val[i]) || (typeof values[i]) === 'string' ? val[i] : Number.parseInt(val[i], 10);
|
|
1614
|
+
const _expected = Number.isNaN(values[i]) || (typeof values[i]) === 'string' ? values[i] : Number.parseInt(values[i], 10);
|
|
1615
|
+
if (_actual !== _expected) return false;
|
|
1534
1616
|
}
|
|
1535
1617
|
return true;
|
|
1536
1618
|
});
|
|
@@ -1589,10 +1671,9 @@ class WebDriver extends Helper {
|
|
|
1589
1671
|
}
|
|
1590
1672
|
|
|
1591
1673
|
/**
|
|
1592
|
-
* {{> executeScript }}
|
|
1593
|
-
*
|
|
1594
|
-
*
|
|
1595
1674
|
* Wraps [execute](http://webdriver.io/api/protocol/execute.html) command.
|
|
1675
|
+
*
|
|
1676
|
+
* {{> executeScript }}
|
|
1596
1677
|
*/
|
|
1597
1678
|
executeScript(...args) {
|
|
1598
1679
|
return this.browser.execute.apply(this.browser, args);
|
|
@@ -1655,7 +1736,11 @@ class WebDriver extends Helper {
|
|
|
1655
1736
|
const res = await this._locate(withStrictLocator(locator), true);
|
|
1656
1737
|
assertElementExists(res, locator);
|
|
1657
1738
|
const elem = usingFirstElement(res);
|
|
1658
|
-
|
|
1739
|
+
try {
|
|
1740
|
+
await elem.moveTo({ xOffset, yOffset });
|
|
1741
|
+
} catch (e) {
|
|
1742
|
+
debug(e.message);
|
|
1743
|
+
}
|
|
1659
1744
|
}
|
|
1660
1745
|
|
|
1661
1746
|
/**
|
|
@@ -1714,11 +1799,8 @@ class WebDriver extends Helper {
|
|
|
1714
1799
|
}
|
|
1715
1800
|
|
|
1716
1801
|
/**
|
|
1802
|
+
* Uses Selenium's JSON [cookie format](https://code.google.com/p/selenium/wiki/JsonWireProtocol#Cookie_JSON_Object).
|
|
1717
1803
|
* {{> setCookie }}
|
|
1718
|
-
*
|
|
1719
|
-
*
|
|
1720
|
-
* Uses Selenium's JSON [cookie
|
|
1721
|
-
* format](https://code.google.com/p/selenium/wiki/JsonWireProtocol#Cookie_JSON_Object).
|
|
1722
1804
|
*/
|
|
1723
1805
|
async setCookie(cookie) {
|
|
1724
1806
|
return this.browser.setCookies(cookie);
|
|
@@ -1771,7 +1853,7 @@ class WebDriver extends Helper {
|
|
|
1771
1853
|
}
|
|
1772
1854
|
|
|
1773
1855
|
/**
|
|
1774
|
-
* Dismisses the active JavaScript popup, as created by window.alert|window.confirm|window.prompt
|
|
1856
|
+
* Dismisses the active JavaScript popup, as created by `window.alert|window.confirm|window.prompt`.
|
|
1775
1857
|
*
|
|
1776
1858
|
*/
|
|
1777
1859
|
async cancelPopup() {
|
|
@@ -1845,9 +1927,9 @@ class WebDriver extends Helper {
|
|
|
1845
1927
|
}
|
|
1846
1928
|
|
|
1847
1929
|
/**
|
|
1848
|
-
* {{> pressKeyWithKeyNormalization }}
|
|
1849
|
-
*
|
|
1850
1930
|
* _Note:_ In case a text field or textarea is focused be aware that some browsers do not respect active modifier when combining modifier keys with other keys.
|
|
1931
|
+
*
|
|
1932
|
+
* {{> pressKeyWithKeyNormalization }}
|
|
1851
1933
|
*/
|
|
1852
1934
|
async pressKey(key) {
|
|
1853
1935
|
const modifiers = [];
|
|
@@ -1906,11 +1988,12 @@ class WebDriver extends Helper {
|
|
|
1906
1988
|
}
|
|
1907
1989
|
|
|
1908
1990
|
/**
|
|
1909
|
-
* {{> resizeWindow }}
|
|
1910
1991
|
* Appium: not tested in web, in apps doesn't work
|
|
1992
|
+
*
|
|
1993
|
+
* {{> resizeWindow }}
|
|
1911
1994
|
*/
|
|
1912
1995
|
async resizeWindow(width, height) {
|
|
1913
|
-
return this.
|
|
1996
|
+
return this.browser.setWindowSize(width, height);
|
|
1914
1997
|
}
|
|
1915
1998
|
|
|
1916
1999
|
async _resizeBrowserWindow(browser, width, height) {
|
|
@@ -1935,8 +2018,32 @@ class WebDriver extends Helper {
|
|
|
1935
2018
|
}
|
|
1936
2019
|
|
|
1937
2020
|
/**
|
|
1938
|
-
* {{>
|
|
2021
|
+
* {{> focus }}
|
|
2022
|
+
*
|
|
2023
|
+
*/
|
|
2024
|
+
async focus(locator) {
|
|
2025
|
+
const els = await this._locate(locator);
|
|
2026
|
+
assertElementExists(els, locator, 'Element to focus');
|
|
2027
|
+
const el = usingFirstElement(els);
|
|
2028
|
+
|
|
2029
|
+
await focusElement(el, this.browser);
|
|
2030
|
+
}
|
|
2031
|
+
|
|
2032
|
+
/**
|
|
2033
|
+
* {{> blur }}
|
|
2034
|
+
*
|
|
2035
|
+
*/
|
|
2036
|
+
async blur(locator) {
|
|
2037
|
+
const els = await this._locate(locator);
|
|
2038
|
+
assertElementExists(els, locator, 'Element to blur');
|
|
2039
|
+
const el = usingFirstElement(els);
|
|
2040
|
+
|
|
2041
|
+
await blurElement(el, this.browser);
|
|
2042
|
+
}
|
|
2043
|
+
|
|
2044
|
+
/**
|
|
1939
2045
|
* Appium: not tested
|
|
2046
|
+
* {{> dragAndDrop }}
|
|
1940
2047
|
*/
|
|
1941
2048
|
async dragAndDrop(srcElement, destElement) {
|
|
1942
2049
|
let sourceEl = await this._locate(srcElement);
|
|
@@ -2036,7 +2143,9 @@ class WebDriver extends Helper {
|
|
|
2036
2143
|
* {{> wait }}
|
|
2037
2144
|
*/
|
|
2038
2145
|
async wait(sec) {
|
|
2039
|
-
return new Promise(resolve =>
|
|
2146
|
+
return new Promise(resolve => {
|
|
2147
|
+
setTimeout(resolve, sec * 1000);
|
|
2148
|
+
});
|
|
2040
2149
|
}
|
|
2041
2150
|
|
|
2042
2151
|
/**
|
|
@@ -2141,20 +2250,18 @@ class WebDriver extends Helper {
|
|
|
2141
2250
|
const aSec = sec || this.options.waitForTimeoutInSeconds;
|
|
2142
2251
|
const _context = context || this.root;
|
|
2143
2252
|
|
|
2144
|
-
return this.browser.waitUntil(
|
|
2145
|
-
|
|
2146
|
-
|
|
2147
|
-
|
|
2148
|
-
|
|
2149
|
-
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2156
|
-
},
|
|
2157
|
-
);
|
|
2253
|
+
return this.browser.waitUntil(async () => {
|
|
2254
|
+
const res = await this.$$(withStrictLocator.call(this, _context));
|
|
2255
|
+
if (!res || res.length === 0) return false;
|
|
2256
|
+
const selected = await forEachAsync(res, async el => this.browser.getElementText(getElementId(el)));
|
|
2257
|
+
if (Array.isArray(selected)) {
|
|
2258
|
+
return selected.filter(part => part.indexOf(text) >= 0).length > 0;
|
|
2259
|
+
}
|
|
2260
|
+
return selected.indexOf(text) >= 0;
|
|
2261
|
+
}, {
|
|
2262
|
+
timeout: aSec * 1000,
|
|
2263
|
+
timeoutMsg: `element (${_context}) is not in DOM or there is no element(${_context}) with text "${text}" after ${aSec} sec`,
|
|
2264
|
+
});
|
|
2158
2265
|
}
|
|
2159
2266
|
|
|
2160
2267
|
/**
|
|
@@ -2164,20 +2271,18 @@ class WebDriver extends Helper {
|
|
|
2164
2271
|
const client = this.browser;
|
|
2165
2272
|
const aSec = sec || this.options.waitForTimeoutInSeconds;
|
|
2166
2273
|
|
|
2167
|
-
return client.waitUntil(
|
|
2168
|
-
|
|
2169
|
-
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
},
|
|
2180
|
-
);
|
|
2274
|
+
return client.waitUntil(async () => {
|
|
2275
|
+
const res = await findFields.call(this, field);
|
|
2276
|
+
if (!res || res.length === 0) return false;
|
|
2277
|
+
const selected = await forEachAsync(res, async el => el.getValue());
|
|
2278
|
+
if (Array.isArray(selected)) {
|
|
2279
|
+
return selected.filter(part => part.indexOf(value) >= 0).length > 0;
|
|
2280
|
+
}
|
|
2281
|
+
return selected.indexOf(value) >= 0;
|
|
2282
|
+
}, {
|
|
2283
|
+
timeout: aSec * 1000,
|
|
2284
|
+
timeoutMsg: `element (${field}) is not in DOM or there is no element(${field}) with value "${value}" after ${aSec} sec`,
|
|
2285
|
+
});
|
|
2181
2286
|
}
|
|
2182
2287
|
|
|
2183
2288
|
/**
|
|
@@ -2269,12 +2374,33 @@ class WebDriver extends Helper {
|
|
|
2269
2374
|
return this.browser.waitUntil(async () => this.browser.execute(fn, ...args), { timeout: aSec * 1000, timeoutMsg: '' });
|
|
2270
2375
|
}
|
|
2271
2376
|
|
|
2377
|
+
/**
|
|
2378
|
+
* {{> waitForNumberOfTabs }}
|
|
2379
|
+
*/
|
|
2380
|
+
async waitForNumberOfTabs(expectedTabs, sec) {
|
|
2381
|
+
const waitTimeout = sec ? sec * 1000 : this.options.waitForTimeoutInSeconds;
|
|
2382
|
+
let currentTabs;
|
|
2383
|
+
let count = 0;
|
|
2384
|
+
|
|
2385
|
+
do {
|
|
2386
|
+
currentTabs = await this.grabNumberOfOpenTabs();
|
|
2387
|
+
await this.wait(1);
|
|
2388
|
+
count += 1000;
|
|
2389
|
+
if (currentTabs >= expectedTabs) return;
|
|
2390
|
+
} while (count <= waitTimeout);
|
|
2391
|
+
|
|
2392
|
+
throw new Error(`Expected ${expectedTabs} tabs are not met after ${waitTimeout / 1000} sec.`);
|
|
2393
|
+
}
|
|
2394
|
+
|
|
2272
2395
|
/**
|
|
2273
2396
|
* {{> switchTo }}
|
|
2274
2397
|
*/
|
|
2275
2398
|
async switchTo(locator) {
|
|
2276
2399
|
this.browser.isInsideFrame = true;
|
|
2277
2400
|
if (Number.isInteger(locator)) {
|
|
2401
|
+
if (this.options.automationProtocol) {
|
|
2402
|
+
return this.browser.switchToFrame(locator + 1);
|
|
2403
|
+
}
|
|
2278
2404
|
return this.browser.switchToFrame(locator);
|
|
2279
2405
|
}
|
|
2280
2406
|
if (!locator) {
|
|
@@ -2385,8 +2511,11 @@ class WebDriver extends Helper {
|
|
|
2385
2511
|
const body = document.body;
|
|
2386
2512
|
const html = document.documentElement;
|
|
2387
2513
|
window.scrollTo(0, Math.max(
|
|
2388
|
-
body.scrollHeight,
|
|
2389
|
-
|
|
2514
|
+
body.scrollHeight,
|
|
2515
|
+
body.offsetHeight,
|
|
2516
|
+
html.clientHeight,
|
|
2517
|
+
html.scrollHeight,
|
|
2518
|
+
html.offsetHeight
|
|
2390
2519
|
));
|
|
2391
2520
|
});
|
|
2392
2521
|
/* eslint-enable */
|
|
@@ -2408,21 +2537,41 @@ class WebDriver extends Helper {
|
|
|
2408
2537
|
}
|
|
2409
2538
|
|
|
2410
2539
|
/**
|
|
2540
|
+
* This method is **deprecated**.
|
|
2541
|
+
*
|
|
2542
|
+
*
|
|
2411
2543
|
* {{> setGeoLocation }}
|
|
2412
2544
|
*/
|
|
2413
|
-
async setGeoLocation(latitude, longitude
|
|
2414
|
-
if (
|
|
2415
|
-
|
|
2545
|
+
async setGeoLocation(latitude, longitude) {
|
|
2546
|
+
if (!this.options.automationProtocol) {
|
|
2547
|
+
console.log(`setGeoLocation deprecated:
|
|
2548
|
+
* This command is deprecated due to using deprecated JSON Wire Protocol command. More info: https://webdriver.io/docs/api/jsonwp/#setgeolocation
|
|
2549
|
+
* Switch to devtools protocol to use this command by setting devtoolsProtocol: true in the configuration`);
|
|
2550
|
+
return;
|
|
2416
2551
|
}
|
|
2417
|
-
|
|
2552
|
+
this.geoLocation = { latitude, longitude };
|
|
2553
|
+
const puppeteerBrowser = await this.browser.getPuppeteer();
|
|
2554
|
+
await this.browser.call(async () => {
|
|
2555
|
+
const pages = await puppeteerBrowser.pages();
|
|
2556
|
+
await pages[0].setGeolocation({ latitude, longitude });
|
|
2557
|
+
});
|
|
2418
2558
|
}
|
|
2419
2559
|
|
|
2420
2560
|
/**
|
|
2561
|
+
* This method is **deprecated**.
|
|
2562
|
+
*
|
|
2421
2563
|
* {{> grabGeoLocation }}
|
|
2422
2564
|
*
|
|
2423
2565
|
*/
|
|
2424
2566
|
async grabGeoLocation() {
|
|
2425
|
-
|
|
2567
|
+
if (!this.options.automationProtocol) {
|
|
2568
|
+
console.log(`grabGeoLocation deprecated:
|
|
2569
|
+
* This command is deprecated due to using deprecated JSON Wire Protocol command. More info: https://webdriver.io/docs/api/jsonwp/#getgeolocation
|
|
2570
|
+
* Switch to devtools protocol to use this command by setting devtoolsProtocol: true in the configuration`);
|
|
2571
|
+
return;
|
|
2572
|
+
}
|
|
2573
|
+
if (!this.geoLocation) return 'No GeoLocation is set!';
|
|
2574
|
+
return this.geoLocation;
|
|
2426
2575
|
}
|
|
2427
2576
|
|
|
2428
2577
|
/**
|
|
@@ -2618,7 +2767,7 @@ async function proceedSeeField(assertType, field, value) {
|
|
|
2618
2767
|
}
|
|
2619
2768
|
};
|
|
2620
2769
|
|
|
2621
|
-
const proceedSingle = el =>
|
|
2770
|
+
const proceedSingle = el => el.getValue().then((res) => {
|
|
2622
2771
|
if (res === null) {
|
|
2623
2772
|
throw new Error(`Element ${el.selector} has no value attribute`);
|
|
2624
2773
|
}
|
|
@@ -2888,9 +3037,9 @@ function isModifierKey(key) {
|
|
|
2888
3037
|
}
|
|
2889
3038
|
|
|
2890
3039
|
function highlightActiveElement(element) {
|
|
2891
|
-
if (
|
|
2892
|
-
|
|
2893
|
-
|
|
3040
|
+
if (this.options.highlightElement && global.debugMode) {
|
|
3041
|
+
highlightElement(element, this.browser);
|
|
3042
|
+
}
|
|
2894
3043
|
}
|
|
2895
3044
|
|
|
2896
3045
|
function prepareLocateFn(context) {
|
|
@@ -5,7 +5,8 @@ const Locator = require('../../locator');
|
|
|
5
5
|
*/
|
|
6
6
|
class ElementNotFound {
|
|
7
7
|
constructor(
|
|
8
|
-
locator,
|
|
8
|
+
locator,
|
|
9
|
+
prefixMessage = 'Element',
|
|
9
10
|
postfixMessage = 'was not found by text|CSS|XPath',
|
|
10
11
|
) {
|
|
11
12
|
if (typeof locator === 'object') {
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
async function findReact(matcher, locator) {
|
|
2
|
+
let _locator = `_react=${locator.react}`;
|
|
3
|
+
let props = '';
|
|
4
|
+
|
|
5
|
+
if (locator.props) {
|
|
6
|
+
props += propBuilder(locator.props);
|
|
7
|
+
_locator += props;
|
|
8
|
+
}
|
|
9
|
+
return matcher.locator(_locator).all();
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
async function findVue(matcher, locator) {
|
|
13
|
+
let _locator = `_vue=${locator.vue}`;
|
|
14
|
+
let props = '';
|
|
15
|
+
|
|
16
|
+
if (locator.props) {
|
|
17
|
+
props += propBuilder(locator.props);
|
|
18
|
+
_locator += props;
|
|
19
|
+
}
|
|
20
|
+
return matcher.locator(_locator).all();
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
function propBuilder(props) {
|
|
24
|
+
let _props = '';
|
|
25
|
+
|
|
26
|
+
for (const [key, value] of Object.entries(props)) {
|
|
27
|
+
if (typeof value === 'object') {
|
|
28
|
+
for (const [k, v] of Object.entries(value)) {
|
|
29
|
+
_props += `[${key}.${k} = "${v}"]`;
|
|
30
|
+
}
|
|
31
|
+
} else {
|
|
32
|
+
_props += `[${key} = "${value}"]`;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return _props;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
module.exports = { findReact, findVue };
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
module.exports.blurElement = (element, context) => {
|
|
2
|
+
const clientSideBlurFn = el => {
|
|
3
|
+
el.blur();
|
|
4
|
+
};
|
|
5
|
+
|
|
6
|
+
try {
|
|
7
|
+
// Puppeteer
|
|
8
|
+
context.evaluate(clientSideBlurFn, element);
|
|
9
|
+
} catch (e) {
|
|
10
|
+
// WebDriver
|
|
11
|
+
try {
|
|
12
|
+
context.execute(clientSideBlurFn, element);
|
|
13
|
+
} catch (err) {
|
|
14
|
+
// ignore
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
};
|