codeceptjs 4.0.0-beta.2 → 4.0.0-beta.21
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 +133 -120
- package/bin/codecept.js +107 -96
- package/bin/test-server.js +64 -0
- package/docs/webapi/clearCookie.mustache +1 -1
- package/docs/webapi/click.mustache +5 -1
- package/lib/actor.js +73 -103
- package/lib/ai.js +159 -188
- package/lib/assert/empty.js +22 -24
- package/lib/assert/equal.js +30 -37
- package/lib/assert/error.js +14 -14
- package/lib/assert/include.js +43 -48
- package/lib/assert/throws.js +11 -11
- package/lib/assert/truth.js +22 -22
- package/lib/assert.js +20 -18
- package/lib/codecept.js +262 -162
- package/lib/colorUtils.js +50 -52
- package/lib/command/check.js +206 -0
- package/lib/command/configMigrate.js +56 -51
- package/lib/command/definitions.js +96 -109
- package/lib/command/dryRun.js +77 -79
- package/lib/command/generate.js +234 -194
- package/lib/command/gherkin/init.js +42 -33
- package/lib/command/gherkin/snippets.js +76 -74
- package/lib/command/gherkin/steps.js +20 -17
- package/lib/command/info.js +74 -38
- package/lib/command/init.js +301 -290
- package/lib/command/interactive.js +41 -32
- package/lib/command/list.js +28 -27
- package/lib/command/run-multiple/chunk.js +51 -48
- package/lib/command/run-multiple/collection.js +5 -5
- package/lib/command/run-multiple/run.js +5 -1
- package/lib/command/run-multiple.js +97 -97
- package/lib/command/run-rerun.js +19 -25
- package/lib/command/run-workers.js +68 -92
- package/lib/command/run.js +39 -27
- package/lib/command/utils.js +80 -64
- package/lib/command/workers/runTests.js +388 -226
- package/lib/config.js +109 -50
- package/lib/container.js +765 -261
- package/lib/data/context.js +60 -61
- package/lib/data/dataScenarioConfig.js +47 -47
- package/lib/data/dataTableArgument.js +32 -32
- package/lib/data/table.js +22 -22
- package/lib/effects.js +307 -0
- package/lib/element/WebElement.js +327 -0
- package/lib/els.js +160 -0
- package/lib/event.js +173 -163
- package/lib/globals.js +141 -0
- package/lib/heal.js +89 -85
- package/lib/helper/AI.js +131 -41
- package/lib/helper/ApiDataFactory.js +107 -75
- package/lib/helper/Appium.js +542 -404
- package/lib/helper/FileSystem.js +100 -79
- package/lib/helper/GraphQL.js +44 -43
- package/lib/helper/GraphQLDataFactory.js +52 -52
- package/lib/helper/JSONResponse.js +126 -88
- package/lib/helper/Mochawesome.js +54 -29
- package/lib/helper/Playwright.js +2547 -1316
- package/lib/helper/Puppeteer.js +1578 -1181
- package/lib/helper/REST.js +209 -68
- package/lib/helper/WebDriver.js +1482 -1342
- package/lib/helper/errors/ConnectionRefused.js +6 -6
- package/lib/helper/errors/ElementAssertion.js +11 -16
- package/lib/helper/errors/ElementNotFound.js +5 -9
- package/lib/helper/errors/RemoteBrowserConnectionRefused.js +5 -5
- package/lib/helper/extras/Console.js +11 -11
- package/lib/helper/extras/PlaywrightLocator.js +110 -0
- package/lib/helper/extras/PlaywrightPropEngine.js +18 -18
- package/lib/helper/extras/PlaywrightReactVueLocator.js +17 -8
- package/lib/helper/extras/PlaywrightRestartOpts.js +25 -11
- package/lib/helper/extras/Popup.js +22 -22
- package/lib/helper/extras/React.js +27 -28
- package/lib/helper/network/actions.js +36 -42
- package/lib/helper/network/utils.js +78 -84
- package/lib/helper/scripts/blurElement.js +5 -5
- package/lib/helper/scripts/focusElement.js +5 -5
- package/lib/helper/scripts/highlightElement.js +8 -8
- package/lib/helper/scripts/isElementClickable.js +34 -34
- package/lib/helper.js +2 -3
- package/lib/history.js +23 -19
- package/lib/hooks.js +8 -8
- package/lib/html.js +94 -104
- package/lib/index.js +38 -27
- package/lib/listener/config.js +30 -23
- package/lib/listener/emptyRun.js +54 -0
- package/lib/listener/enhancedGlobalRetry.js +110 -0
- package/lib/listener/exit.js +16 -18
- package/lib/listener/globalRetry.js +70 -0
- package/lib/listener/globalTimeout.js +181 -0
- package/lib/listener/helpers.js +76 -51
- package/lib/listener/mocha.js +10 -11
- package/lib/listener/result.js +11 -0
- package/lib/listener/retryEnhancer.js +85 -0
- package/lib/listener/steps.js +71 -59
- package/lib/listener/store.js +20 -0
- package/lib/locator.js +214 -197
- package/lib/mocha/asyncWrapper.js +274 -0
- package/lib/mocha/bdd.js +167 -0
- package/lib/mocha/cli.js +341 -0
- package/lib/mocha/factory.js +163 -0
- package/lib/mocha/featureConfig.js +89 -0
- package/lib/mocha/gherkin.js +231 -0
- package/lib/mocha/hooks.js +121 -0
- package/lib/mocha/index.js +21 -0
- package/lib/mocha/inject.js +46 -0
- package/lib/{interfaces → mocha}/scenarioConfig.js +58 -34
- package/lib/mocha/suite.js +89 -0
- package/lib/mocha/test.js +184 -0
- package/lib/mocha/types.d.ts +42 -0
- package/lib/mocha/ui.js +242 -0
- package/lib/output.js +141 -71
- package/lib/parser.js +54 -44
- package/lib/pause.js +173 -145
- package/lib/plugin/analyze.js +403 -0
- package/lib/plugin/{autoLogin.js → auth.js} +178 -79
- package/lib/plugin/autoDelay.js +36 -40
- package/lib/plugin/coverage.js +131 -78
- package/lib/plugin/customLocator.js +22 -21
- package/lib/plugin/customReporter.js +53 -0
- package/lib/plugin/enhancedRetryFailedStep.js +99 -0
- package/lib/plugin/heal.js +101 -110
- package/lib/plugin/htmlReporter.js +3648 -0
- package/lib/plugin/pageInfo.js +140 -0
- package/lib/plugin/pauseOnFail.js +12 -11
- package/lib/plugin/retryFailedStep.js +82 -47
- package/lib/plugin/screenshotOnFail.js +111 -92
- package/lib/plugin/stepByStepReport.js +159 -101
- package/lib/plugin/stepTimeout.js +20 -25
- package/lib/plugin/subtitles.js +38 -38
- package/lib/recorder.js +193 -130
- package/lib/rerun.js +94 -49
- package/lib/result.js +238 -0
- package/lib/retryCoordinator.js +207 -0
- package/lib/secret.js +20 -18
- package/lib/session.js +95 -89
- package/lib/step/base.js +239 -0
- package/lib/step/comment.js +10 -0
- package/lib/step/config.js +50 -0
- package/lib/step/func.js +46 -0
- package/lib/step/helper.js +50 -0
- package/lib/step/meta.js +99 -0
- package/lib/step/record.js +74 -0
- package/lib/step/retry.js +11 -0
- package/lib/step/section.js +55 -0
- package/lib/step.js +18 -329
- package/lib/steps.js +54 -0
- package/lib/store.js +38 -7
- package/lib/template/heal.js +3 -12
- package/lib/template/prompts/generatePageObject.js +31 -0
- package/lib/template/prompts/healStep.js +13 -0
- package/lib/template/prompts/writeStep.js +9 -0
- package/lib/test-server.js +334 -0
- package/lib/timeout.js +60 -0
- package/lib/transform.js +8 -8
- package/lib/translation.js +34 -21
- package/lib/utils/loaderCheck.js +124 -0
- package/lib/utils/mask_data.js +47 -0
- package/lib/utils/typescript.js +237 -0
- package/lib/utils.js +411 -228
- package/lib/workerStorage.js +37 -34
- package/lib/workers.js +532 -296
- package/package.json +124 -95
- package/translations/de-DE.js +5 -3
- package/translations/fr-FR.js +5 -4
- package/translations/index.js +22 -12
- package/translations/it-IT.js +4 -3
- package/translations/ja-JP.js +4 -3
- package/translations/nl-NL.js +76 -0
- package/translations/pl-PL.js +4 -3
- package/translations/pt-BR.js +4 -3
- package/translations/ru-RU.js +4 -3
- package/translations/utils.js +10 -0
- package/translations/zh-CN.js +4 -3
- package/translations/zh-TW.js +4 -3
- package/typings/index.d.ts +546 -185
- package/typings/promiseBasedTypes.d.ts +150 -875
- package/typings/types.d.ts +547 -992
- package/lib/cli.js +0 -249
- package/lib/dirname.js +0 -5
- package/lib/helper/Expect.js +0 -425
- package/lib/helper/ExpectHelper.js +0 -399
- package/lib/helper/MockServer.js +0 -223
- package/lib/helper/Nightmare.js +0 -1411
- package/lib/helper/Protractor.js +0 -1835
- package/lib/helper/SoftExpectHelper.js +0 -381
- package/lib/helper/TestCafe.js +0 -1410
- package/lib/helper/clientscripts/nightmare.js +0 -213
- package/lib/helper/testcafe/testControllerHolder.js +0 -42
- package/lib/helper/testcafe/testcafe-utils.js +0 -63
- package/lib/interfaces/bdd.js +0 -98
- package/lib/interfaces/featureConfig.js +0 -69
- package/lib/interfaces/gherkin.js +0 -195
- package/lib/listener/artifacts.js +0 -19
- package/lib/listener/retry.js +0 -68
- package/lib/listener/timeout.js +0 -109
- package/lib/mochaFactory.js +0 -110
- package/lib/plugin/allure.js +0 -15
- package/lib/plugin/commentStep.js +0 -136
- package/lib/plugin/debugErrors.js +0 -67
- package/lib/plugin/eachElement.js +0 -127
- package/lib/plugin/fakerTransform.js +0 -49
- package/lib/plugin/retryTo.js +0 -121
- package/lib/plugin/selenoid.js +0 -371
- package/lib/plugin/standardActingHelpers.js +0 -9
- package/lib/plugin/tryTo.js +0 -105
- package/lib/plugin/wdio.js +0 -246
- package/lib/scenario.js +0 -222
- package/lib/ui.js +0 -238
- package/lib/within.js +0 -70
package/lib/helper/Appium.js
CHANGED
|
@@ -1,25 +1,27 @@
|
|
|
1
|
-
import
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
5
|
-
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import
|
|
9
|
-
import
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
1
|
+
import * as webdriverio from 'webdriverio'
|
|
2
|
+
import fs from 'fs'
|
|
3
|
+
import axios from 'axios'
|
|
4
|
+
import { v4 as uuidv4 } from 'uuid'
|
|
5
|
+
|
|
6
|
+
import Webdriver from './WebDriver.js'
|
|
7
|
+
import AssertionFailedError from '../assert/error.js'
|
|
8
|
+
import { truth } from '../assert/truth.js'
|
|
9
|
+
import recorder from '../recorder.js'
|
|
10
|
+
import Locator from '../locator.js'
|
|
11
|
+
import ConnectionRefused from './errors/ConnectionRefused.js'
|
|
12
|
+
import ElementNotFound from './errors/ElementNotFound.js'
|
|
13
|
+
import { dontSeeElementError } from './errors/ElementAssertion.js'
|
|
14
|
+
|
|
15
|
+
const mobileRoot = '//*'
|
|
16
|
+
const webRoot = 'body'
|
|
15
17
|
const supportedPlatform = {
|
|
16
18
|
android: 'Android',
|
|
17
19
|
iOS: 'iOS',
|
|
18
|
-
}
|
|
20
|
+
}
|
|
19
21
|
|
|
20
22
|
const vendorPrefix = {
|
|
21
23
|
appium: 'appium',
|
|
22
|
-
}
|
|
24
|
+
}
|
|
23
25
|
|
|
24
26
|
/**
|
|
25
27
|
* Appium helper extends [Webdriver](http://codecept.io/helpers/WebDriver/) helper.
|
|
@@ -43,7 +45,7 @@ const vendorPrefix = {
|
|
|
43
45
|
*
|
|
44
46
|
* This helper should be configured in codecept.conf.ts or codecept.conf.js
|
|
45
47
|
*
|
|
46
|
-
* * `appiumV2`: set this to
|
|
48
|
+
* * `appiumV2`: by default is true, set this to false if you want to run tests with AppiumV1. See more how to setup [here](https://codecept.io/mobile/#setting-up)
|
|
47
49
|
* * `app`: Application path. Local path or remote URL to an .ipa or .apk file, or a .zip containing one of these. Alias to desiredCapabilities.appPackage
|
|
48
50
|
* * `host`: (default: 'localhost') Appium host
|
|
49
51
|
* * `port`: (default: '4723') Appium port
|
|
@@ -123,7 +125,7 @@ const vendorPrefix = {
|
|
|
123
125
|
* {
|
|
124
126
|
* helpers: {
|
|
125
127
|
* Appium: {
|
|
126
|
-
* appiumV2: true,
|
|
128
|
+
* appiumV2: true, // By default is true, set to false if you want to run against Appium v1
|
|
127
129
|
* host: "hub-cloud.browserstack.com",
|
|
128
130
|
* port: 4444,
|
|
129
131
|
* user: process.env.BROWSERSTACK_USER,
|
|
@@ -174,19 +176,16 @@ class Appium extends Webdriver {
|
|
|
174
176
|
|
|
175
177
|
// @ts-ignore
|
|
176
178
|
constructor(config) {
|
|
177
|
-
super(config)
|
|
179
|
+
super(config)
|
|
178
180
|
|
|
179
|
-
this.isRunning = false
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
}
|
|
183
|
-
this.axios = axios.create();
|
|
181
|
+
this.isRunning = false
|
|
182
|
+
this.appiumV2 = config.appiumV2 || true
|
|
183
|
+
this.axios = axios.create()
|
|
184
184
|
|
|
185
|
-
webdriverio = require('webdriverio');
|
|
186
185
|
if (!config.appiumV2) {
|
|
187
|
-
console.log('The Appium core team does not maintain Appium 1.x anymore since the 1st of January 2022.
|
|
188
|
-
console.log('More info: https://bit.ly/appium-v2-migration')
|
|
189
|
-
console.log('This Appium 1.x support will be removed in next major release.')
|
|
186
|
+
console.log('The Appium core team does not maintain Appium 1.x anymore since the 1st of January 2022. Appium 2.x is used by default.')
|
|
187
|
+
console.log('More info: https://bit.ly/appium-v2-migration')
|
|
188
|
+
console.log('This Appium 1.x support will be removed in next major release.')
|
|
190
189
|
}
|
|
191
190
|
}
|
|
192
191
|
|
|
@@ -203,7 +202,7 @@ class Appium extends Webdriver {
|
|
|
203
202
|
}
|
|
204
203
|
}
|
|
205
204
|
}
|
|
206
|
-
`)
|
|
205
|
+
`)
|
|
207
206
|
}
|
|
208
207
|
|
|
209
208
|
// set defaults
|
|
@@ -224,166 +223,195 @@ class Appium extends Webdriver {
|
|
|
224
223
|
timeouts: {
|
|
225
224
|
script: 0, // ms
|
|
226
225
|
},
|
|
227
|
-
}
|
|
226
|
+
}
|
|
228
227
|
|
|
229
228
|
// override defaults with config
|
|
230
|
-
config = Object.assign(defaults, config)
|
|
229
|
+
config = Object.assign(defaults, config)
|
|
231
230
|
|
|
232
|
-
config.baseUrl = config.url || config.baseUrl
|
|
231
|
+
config.baseUrl = config.url || config.baseUrl
|
|
233
232
|
if (config.desiredCapabilities && Object.keys(config.desiredCapabilities).length) {
|
|
234
|
-
config.capabilities = this.appiumV2 === true ? this._convertAppiumV2Caps(config.desiredCapabilities) : config.desiredCapabilities
|
|
233
|
+
config.capabilities = this.appiumV2 === true ? this._convertAppiumV2Caps(config.desiredCapabilities) : config.desiredCapabilities
|
|
235
234
|
}
|
|
236
235
|
|
|
237
236
|
if (this.appiumV2) {
|
|
238
|
-
config.capabilities[`${vendorPrefix.appium}:deviceName`] = config[`${vendorPrefix.appium}:device`] || config.capabilities[`${vendorPrefix.appium}:deviceName`]
|
|
239
|
-
config.capabilities[`${vendorPrefix.appium}:browserName`] = config[`${vendorPrefix.appium}:browser`] || config.capabilities[`${vendorPrefix.appium}:browserName`]
|
|
240
|
-
config.capabilities[`${vendorPrefix.appium}:app`] = config[`${vendorPrefix.appium}:app`] || config.capabilities[`${vendorPrefix.appium}:app`]
|
|
241
|
-
config.capabilities[`${vendorPrefix.appium}:tunnelIdentifier`] = config[`${vendorPrefix.appium}:tunnelIdentifier`] || config.capabilities[`${vendorPrefix.appium}:tunnelIdentifier`]
|
|
237
|
+
config.capabilities[`${vendorPrefix.appium}:deviceName`] = config[`${vendorPrefix.appium}:device`] || config.capabilities[`${vendorPrefix.appium}:deviceName`]
|
|
238
|
+
config.capabilities[`${vendorPrefix.appium}:browserName`] = config[`${vendorPrefix.appium}:browser`] || config.capabilities[`${vendorPrefix.appium}:browserName`]
|
|
239
|
+
config.capabilities[`${vendorPrefix.appium}:app`] = config[`${vendorPrefix.appium}:app`] || config.capabilities[`${vendorPrefix.appium}:app`]
|
|
240
|
+
config.capabilities[`${vendorPrefix.appium}:tunnelIdentifier`] = config[`${vendorPrefix.appium}:tunnelIdentifier`] || config.capabilities[`${vendorPrefix.appium}:tunnelIdentifier`] // Adding the code to connect to sauce labs via sauce tunnel
|
|
242
241
|
} else {
|
|
243
|
-
config.capabilities.deviceName = config.device || config.capabilities.deviceName
|
|
244
|
-
config.capabilities.browserName = config.browser || config.capabilities.browserName
|
|
245
|
-
config.capabilities.app = config.app || config.capabilities.app
|
|
246
|
-
config.capabilities.tunnelIdentifier = config.tunnelIdentifier || config.capabilities.tunnelIdentifier
|
|
242
|
+
config.capabilities.deviceName = config.device || config.capabilities.deviceName
|
|
243
|
+
config.capabilities.browserName = config.browser || config.capabilities.browserName
|
|
244
|
+
config.capabilities.app = config.app || config.capabilities.app
|
|
245
|
+
config.capabilities.tunnelIdentifier = config.tunnelIdentifier || config.capabilities.tunnelIdentifier // Adding the code to connect to sauce labs via sauce tunnel
|
|
247
246
|
}
|
|
248
247
|
|
|
249
|
-
config.capabilities.platformName = config.platform || config.capabilities.platformName
|
|
250
|
-
config.waitForTimeoutInSeconds = config.waitForTimeout / 1000
|
|
248
|
+
config.capabilities.platformName = config.platform || config.capabilities.platformName
|
|
249
|
+
config.waitForTimeoutInSeconds = config.waitForTimeout / 1000 // convert to seconds
|
|
251
250
|
|
|
252
251
|
// [CodeceptJS compatible] transform host to hostname
|
|
253
|
-
config.hostname = config.host || config.hostname
|
|
252
|
+
config.hostname = config.host || config.hostname
|
|
254
253
|
|
|
255
254
|
if (!config.app && config.capabilities.browserName) {
|
|
256
|
-
this.isWeb = true
|
|
257
|
-
this.root = webRoot
|
|
255
|
+
this.isWeb = true
|
|
256
|
+
this.root = webRoot
|
|
258
257
|
} else {
|
|
259
|
-
this.isWeb = false
|
|
260
|
-
this.root = mobileRoot
|
|
258
|
+
this.isWeb = false
|
|
259
|
+
this.root = mobileRoot
|
|
261
260
|
}
|
|
262
261
|
|
|
263
|
-
this.platform = null
|
|
262
|
+
this.platform = null
|
|
264
263
|
if (config.capabilities[`${vendorPrefix.appium}:platformName`]) {
|
|
265
|
-
|
|
264
|
+
config.capabilities[`${vendorPrefix.appium}:platformName`] = config.capabilities[`${vendorPrefix.appium}:platformName`].toLowerCase()
|
|
265
|
+
this.platform = config.capabilities[`${vendorPrefix.appium}:platformName`]
|
|
266
266
|
}
|
|
267
267
|
|
|
268
268
|
if (config.capabilities.platformName) {
|
|
269
|
-
|
|
269
|
+
config.capabilities.platformName = config.capabilities.platformName.toLowerCase()
|
|
270
|
+
this.platform = config.capabilities.platformName
|
|
270
271
|
}
|
|
271
272
|
|
|
272
|
-
return config
|
|
273
|
+
return config
|
|
273
274
|
}
|
|
274
275
|
|
|
275
276
|
_convertAppiumV2Caps(capabilities) {
|
|
276
|
-
const _convertedCaps = {}
|
|
277
|
+
const _convertedCaps = {}
|
|
277
278
|
for (const [key, value] of Object.entries(capabilities)) {
|
|
278
279
|
if (!key.startsWith(vendorPrefix.appium)) {
|
|
279
|
-
if (key !== 'platformName' && key !== 'bstack:options') {
|
|
280
|
-
_convertedCaps[`${vendorPrefix.appium}:${key}`] = value
|
|
280
|
+
if (key !== 'platformName' && key !== 'bstack:options' && key !== 'sauce:options') {
|
|
281
|
+
_convertedCaps[`${vendorPrefix.appium}:${key}`] = value
|
|
281
282
|
} else {
|
|
282
|
-
_convertedCaps[`${key}`] = value
|
|
283
|
+
_convertedCaps[`${key}`] = value
|
|
283
284
|
}
|
|
284
285
|
} else {
|
|
285
|
-
_convertedCaps[`${key}`] = value
|
|
286
|
+
_convertedCaps[`${key}`] = value
|
|
286
287
|
}
|
|
287
288
|
}
|
|
288
|
-
return _convertedCaps
|
|
289
|
+
return _convertedCaps
|
|
289
290
|
}
|
|
290
291
|
|
|
291
292
|
static _config() {
|
|
292
|
-
return [
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
293
|
+
return [
|
|
294
|
+
{
|
|
295
|
+
name: 'app',
|
|
296
|
+
message: 'Application package. Path to file or url',
|
|
297
|
+
default: 'http://localhost',
|
|
298
|
+
},
|
|
299
|
+
{
|
|
300
|
+
name: 'platform',
|
|
301
|
+
message: 'Mobile Platform',
|
|
302
|
+
type: 'list',
|
|
303
|
+
choices: ['iOS', supportedPlatform.android],
|
|
304
|
+
default: supportedPlatform.android,
|
|
305
|
+
},
|
|
306
|
+
{
|
|
307
|
+
name: 'device',
|
|
308
|
+
message: 'Device to run tests on',
|
|
309
|
+
default: 'emulator',
|
|
310
|
+
},
|
|
311
|
+
]
|
|
307
312
|
}
|
|
308
313
|
|
|
309
314
|
async _startBrowser() {
|
|
310
315
|
if (this.appiumV2 === true) {
|
|
311
|
-
this.options.capabilities = this._convertAppiumV2Caps(this.options.capabilities)
|
|
312
|
-
this.options.desiredCapabilities = this._convertAppiumV2Caps(this.options.desiredCapabilities)
|
|
316
|
+
this.options.capabilities = this._convertAppiumV2Caps(this.options.capabilities)
|
|
317
|
+
this.options.desiredCapabilities = this._convertAppiumV2Caps(this.options.desiredCapabilities)
|
|
313
318
|
}
|
|
314
319
|
|
|
315
320
|
try {
|
|
316
321
|
if (this.options.multiremote) {
|
|
317
|
-
this.browser = await webdriverio.multiremote(this.options.multiremote)
|
|
322
|
+
this.browser = await webdriverio.multiremote(this.options.multiremote)
|
|
318
323
|
} else {
|
|
319
|
-
this.browser = await webdriverio.remote(this.options)
|
|
324
|
+
this.browser = await webdriverio.remote(this.options)
|
|
320
325
|
}
|
|
321
326
|
} catch (err) {
|
|
322
327
|
if (err.toString().indexOf('ECONNREFUSED')) {
|
|
323
|
-
throw new ConnectionRefused(err)
|
|
328
|
+
throw new ConnectionRefused(err)
|
|
324
329
|
}
|
|
325
|
-
throw err
|
|
330
|
+
throw err
|
|
326
331
|
}
|
|
327
|
-
this.$$ = this.browser.$$.bind(this.browser)
|
|
332
|
+
this.$$ = this.browser.$$.bind(this.browser)
|
|
328
333
|
|
|
329
|
-
this.isRunning = true
|
|
334
|
+
this.isRunning = true
|
|
330
335
|
if (this.options.timeouts && this.isWeb) {
|
|
331
|
-
await this.defineTimeout(this.options.timeouts)
|
|
336
|
+
await this.defineTimeout(this.options.timeouts)
|
|
332
337
|
}
|
|
333
338
|
if (this.options.windowSize === 'maximize' && !this.platform) {
|
|
334
|
-
const res = await this.browser.execute('return [screen.width, screen.height]')
|
|
339
|
+
const res = await this.browser.execute('return [screen.width, screen.height]')
|
|
335
340
|
return this.browser.windowHandleSize({
|
|
336
341
|
width: res.value[0],
|
|
337
342
|
height: res.value[1],
|
|
338
|
-
})
|
|
343
|
+
})
|
|
339
344
|
}
|
|
340
345
|
if (this.options.windowSize && this.options.windowSize.indexOf('x') > 0 && !this.platform) {
|
|
341
|
-
const dimensions = this.options.windowSize.split('x')
|
|
346
|
+
const dimensions = this.options.windowSize.split('x')
|
|
342
347
|
await this.browser.windowHandleSize({
|
|
343
348
|
width: dimensions[0],
|
|
344
349
|
height: dimensions[1],
|
|
345
|
-
})
|
|
350
|
+
})
|
|
346
351
|
}
|
|
347
352
|
}
|
|
348
353
|
|
|
349
354
|
async _after() {
|
|
350
|
-
if (!this.isRunning) return
|
|
355
|
+
if (!this.isRunning) return
|
|
351
356
|
if (this.options.restart) {
|
|
352
|
-
this.isRunning = false
|
|
353
|
-
return this.browser.deleteSession()
|
|
357
|
+
this.isRunning = false
|
|
358
|
+
return this.browser.deleteSession()
|
|
354
359
|
}
|
|
355
360
|
if (this.isWeb && !this.platform) {
|
|
356
|
-
return super._after()
|
|
361
|
+
return super._after()
|
|
357
362
|
}
|
|
358
363
|
}
|
|
359
364
|
|
|
360
365
|
async _withinBegin(context) {
|
|
361
366
|
if (this.isWeb) {
|
|
362
|
-
return super._withinBegin(context)
|
|
367
|
+
return super._withinBegin(context)
|
|
363
368
|
}
|
|
364
369
|
if (context === 'webview') {
|
|
365
|
-
return this.switchToWeb()
|
|
370
|
+
return this.switchToWeb()
|
|
366
371
|
}
|
|
367
372
|
if (typeof context === 'object') {
|
|
368
|
-
if (context.web) return this.switchToWeb(context.web)
|
|
369
|
-
if (context.webview) return this.switchToWeb(context.webview)
|
|
373
|
+
if (context.web) return this.switchToWeb(context.web)
|
|
374
|
+
if (context.webview) return this.switchToWeb(context.webview)
|
|
370
375
|
}
|
|
371
|
-
return this.switchToContext(context)
|
|
376
|
+
return this.switchToContext(context)
|
|
372
377
|
}
|
|
373
378
|
|
|
374
379
|
_withinEnd() {
|
|
375
380
|
if (this.isWeb) {
|
|
376
|
-
return super._withinEnd()
|
|
381
|
+
return super._withinEnd()
|
|
377
382
|
}
|
|
378
|
-
return this.switchToNative()
|
|
383
|
+
return this.switchToNative()
|
|
379
384
|
}
|
|
380
385
|
|
|
381
386
|
_buildAppiumEndpoint() {
|
|
382
|
-
const {
|
|
383
|
-
|
|
384
|
-
|
|
387
|
+
const { protocol, port, hostname, path } = this.browser.options
|
|
388
|
+
// Ensure path does NOT end with a slash to prevent double slashes
|
|
389
|
+
const normalizedPath = path.replace(/\/$/, '')
|
|
385
390
|
// Build path to Appium REST API endpoint
|
|
386
|
-
return `${protocol}://${hostname}:${port}${
|
|
391
|
+
return `${protocol}://${hostname}:${port}${normalizedPath}/session/${this.browser.sessionId}`
|
|
392
|
+
}
|
|
393
|
+
|
|
394
|
+
/**
|
|
395
|
+
* Helper method to safely call isDisplayed() on mobile elements.
|
|
396
|
+
* Handles the case where webdriverio tries to use execute/sync which isn't supported in Appium.
|
|
397
|
+
* @private
|
|
398
|
+
*/
|
|
399
|
+
async _isDisplayedSafe(element) {
|
|
400
|
+
if (this.isWeb) {
|
|
401
|
+
// For web contexts, use the normal isDisplayed
|
|
402
|
+
return element.isDisplayed()
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
try {
|
|
406
|
+
return await element.isDisplayed()
|
|
407
|
+
} catch (err) {
|
|
408
|
+
// If isDisplayed fails due to execute/sync not being supported in native mobile contexts,
|
|
409
|
+
// fall back to assuming the element is displayed (since we found it)
|
|
410
|
+
if (err.message && err.message.includes('Method is not implemented')) {
|
|
411
|
+
return true
|
|
412
|
+
}
|
|
413
|
+
throw err
|
|
414
|
+
}
|
|
387
415
|
}
|
|
388
416
|
|
|
389
417
|
/**
|
|
@@ -421,11 +449,11 @@ class Appium extends Webdriver {
|
|
|
421
449
|
* @param {*} fn
|
|
422
450
|
*/
|
|
423
451
|
async runOnIOS(caps, fn) {
|
|
424
|
-
if (this.platform !== 'ios') return
|
|
425
|
-
recorder.session.start('iOS-only actions')
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
return recorder.promise()
|
|
452
|
+
if (this.platform !== 'ios') return
|
|
453
|
+
recorder.session.start('iOS-only actions')
|
|
454
|
+
this._runWithCaps(caps, fn)
|
|
455
|
+
recorder.add('restore from iOS session', () => recorder.session.restore())
|
|
456
|
+
return recorder.promise()
|
|
429
457
|
}
|
|
430
458
|
|
|
431
459
|
/**
|
|
@@ -463,11 +491,11 @@ class Appium extends Webdriver {
|
|
|
463
491
|
* @param {*} fn
|
|
464
492
|
*/
|
|
465
493
|
async runOnAndroid(caps, fn) {
|
|
466
|
-
if (this.platform !== 'android') return
|
|
467
|
-
recorder.session.start('Android-only actions')
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
return recorder.promise()
|
|
494
|
+
if (this.platform !== 'android') return
|
|
495
|
+
recorder.session.start('Android-only actions')
|
|
496
|
+
this._runWithCaps(caps, fn)
|
|
497
|
+
recorder.add('restore from Android session', () => recorder.session.restore())
|
|
498
|
+
return recorder.promise()
|
|
471
499
|
}
|
|
472
500
|
|
|
473
501
|
/**
|
|
@@ -480,38 +508,36 @@ class Appium extends Webdriver {
|
|
|
480
508
|
* });
|
|
481
509
|
* ```
|
|
482
510
|
*
|
|
483
|
-
* @param {*} fn
|
|
484
511
|
*/
|
|
485
|
-
/* eslint-disable */
|
|
486
|
-
async runInWeb(fn) {
|
|
487
|
-
if (!this.isWeb) return;
|
|
488
|
-
recorder.session.start('Web-only actions');
|
|
489
512
|
|
|
490
|
-
|
|
491
|
-
|
|
513
|
+
async runInWeb() {
|
|
514
|
+
if (!this.isWeb) return
|
|
515
|
+
recorder.session.start('Web-only actions')
|
|
516
|
+
|
|
517
|
+
recorder.add('restore from Web session', () => recorder.session.restore(), true)
|
|
518
|
+
return recorder.promise()
|
|
492
519
|
}
|
|
493
|
-
/* eslint-enable */
|
|
494
520
|
|
|
495
|
-
|
|
521
|
+
_runWithCaps(caps, fn) {
|
|
496
522
|
if (typeof caps === 'object') {
|
|
497
523
|
for (const key in caps) {
|
|
498
524
|
// skip if capabilities do not match
|
|
499
525
|
if (this.config.desiredCapabilities[key] !== caps[key]) {
|
|
500
|
-
return
|
|
526
|
+
return
|
|
501
527
|
}
|
|
502
528
|
}
|
|
503
529
|
}
|
|
504
530
|
if (typeof caps === 'function') {
|
|
505
531
|
if (!fn) {
|
|
506
|
-
fn = caps
|
|
532
|
+
fn = caps
|
|
507
533
|
} else {
|
|
508
534
|
// skip if capabilities are checked inside a function
|
|
509
|
-
const enabled = caps(this.config.desiredCapabilities)
|
|
510
|
-
if (!enabled) return
|
|
535
|
+
const enabled = caps(this.config.desiredCapabilities)
|
|
536
|
+
if (!enabled) return
|
|
511
537
|
}
|
|
512
538
|
}
|
|
513
539
|
|
|
514
|
-
fn()
|
|
540
|
+
fn()
|
|
515
541
|
}
|
|
516
542
|
|
|
517
543
|
/**
|
|
@@ -527,9 +553,9 @@ class Appium extends Webdriver {
|
|
|
527
553
|
* Appium: support only Android
|
|
528
554
|
*/
|
|
529
555
|
async checkIfAppIsInstalled(bundleId) {
|
|
530
|
-
onlyForApps.call(this, supportedPlatform.android)
|
|
556
|
+
onlyForApps.call(this, supportedPlatform.android)
|
|
531
557
|
|
|
532
|
-
return this.browser.isAppInstalled(bundleId)
|
|
558
|
+
return this.browser.isAppInstalled(bundleId)
|
|
533
559
|
}
|
|
534
560
|
|
|
535
561
|
/**
|
|
@@ -545,9 +571,9 @@ class Appium extends Webdriver {
|
|
|
545
571
|
* Appium: support only Android
|
|
546
572
|
*/
|
|
547
573
|
async seeAppIsInstalled(bundleId) {
|
|
548
|
-
onlyForApps.call(this, supportedPlatform.android)
|
|
549
|
-
const res = await this.browser.isAppInstalled(bundleId)
|
|
550
|
-
return truth(`app ${bundleId}`, 'to be installed').assert(res)
|
|
574
|
+
onlyForApps.call(this, supportedPlatform.android)
|
|
575
|
+
const res = await this.browser.isAppInstalled(bundleId)
|
|
576
|
+
return truth(`app ${bundleId}`, 'to be installed').assert(res)
|
|
551
577
|
}
|
|
552
578
|
|
|
553
579
|
/**
|
|
@@ -563,9 +589,9 @@ class Appium extends Webdriver {
|
|
|
563
589
|
* Appium: support only Android
|
|
564
590
|
*/
|
|
565
591
|
async seeAppIsNotInstalled(bundleId) {
|
|
566
|
-
onlyForApps.call(this, supportedPlatform.android)
|
|
567
|
-
const res = await this.browser.isAppInstalled(bundleId)
|
|
568
|
-
return truth(`app ${bundleId}`, 'not to be installed').negate(res)
|
|
592
|
+
onlyForApps.call(this, supportedPlatform.android)
|
|
593
|
+
const res = await this.browser.isAppInstalled(bundleId)
|
|
594
|
+
return truth(`app ${bundleId}`, 'not to be installed').negate(res)
|
|
569
595
|
}
|
|
570
596
|
|
|
571
597
|
/**
|
|
@@ -580,8 +606,8 @@ class Appium extends Webdriver {
|
|
|
580
606
|
* Appium: support only Android
|
|
581
607
|
*/
|
|
582
608
|
async installApp(path) {
|
|
583
|
-
onlyForApps.call(this, supportedPlatform.android)
|
|
584
|
-
return this.browser.installApp(path)
|
|
609
|
+
onlyForApps.call(this, supportedPlatform.android)
|
|
610
|
+
return this.browser.installApp(path)
|
|
585
611
|
}
|
|
586
612
|
|
|
587
613
|
/**
|
|
@@ -597,13 +623,13 @@ class Appium extends Webdriver {
|
|
|
597
623
|
* @param {string} [bundleId] ID of bundle
|
|
598
624
|
*/
|
|
599
625
|
async removeApp(appId, bundleId) {
|
|
600
|
-
onlyForApps.call(this, supportedPlatform.android)
|
|
626
|
+
onlyForApps.call(this, supportedPlatform.android)
|
|
601
627
|
|
|
602
628
|
return this.axios({
|
|
603
629
|
method: 'post',
|
|
604
|
-
url: `${this._buildAppiumEndpoint()}/
|
|
630
|
+
url: `${this._buildAppiumEndpoint()}/appium/device/remove_app`,
|
|
605
631
|
data: { appId, bundleId },
|
|
606
|
-
})
|
|
632
|
+
})
|
|
607
633
|
}
|
|
608
634
|
|
|
609
635
|
/**
|
|
@@ -615,11 +641,12 @@ class Appium extends Webdriver {
|
|
|
615
641
|
*
|
|
616
642
|
*/
|
|
617
643
|
async resetApp() {
|
|
618
|
-
onlyForApps.call(this)
|
|
644
|
+
onlyForApps.call(this)
|
|
645
|
+
this.isWeb = false // Reset to native context after app reset
|
|
619
646
|
return this.axios({
|
|
620
647
|
method: 'post',
|
|
621
|
-
url: `${this._buildAppiumEndpoint()}/
|
|
622
|
-
})
|
|
648
|
+
url: `${this._buildAppiumEndpoint()}/appium/app/reset`,
|
|
649
|
+
})
|
|
623
650
|
}
|
|
624
651
|
|
|
625
652
|
/**
|
|
@@ -634,9 +661,9 @@ class Appium extends Webdriver {
|
|
|
634
661
|
* Appium: support only Android
|
|
635
662
|
*/
|
|
636
663
|
async seeCurrentActivityIs(currentActivity) {
|
|
637
|
-
onlyForApps.call(this, supportedPlatform.android)
|
|
638
|
-
const res = await this.browser.getCurrentActivity()
|
|
639
|
-
return truth('current activity', `to be ${currentActivity}`).assert(res === currentActivity)
|
|
664
|
+
onlyForApps.call(this, supportedPlatform.android)
|
|
665
|
+
const res = await this.browser.getCurrentActivity()
|
|
666
|
+
return truth('current activity', `to be ${currentActivity}`).assert(res === currentActivity)
|
|
640
667
|
}
|
|
641
668
|
|
|
642
669
|
/**
|
|
@@ -651,9 +678,9 @@ class Appium extends Webdriver {
|
|
|
651
678
|
* Appium: support only Android
|
|
652
679
|
*/
|
|
653
680
|
async seeDeviceIsLocked() {
|
|
654
|
-
onlyForApps.call(this, supportedPlatform.android)
|
|
655
|
-
const res = await this.browser.isLocked()
|
|
656
|
-
return truth('device', 'to be locked').assert(res)
|
|
681
|
+
onlyForApps.call(this, supportedPlatform.android)
|
|
682
|
+
const res = await this.browser.isLocked()
|
|
683
|
+
return truth('device', 'to be locked').assert(res)
|
|
657
684
|
}
|
|
658
685
|
|
|
659
686
|
/**
|
|
@@ -668,9 +695,9 @@ class Appium extends Webdriver {
|
|
|
668
695
|
* Appium: support only Android
|
|
669
696
|
*/
|
|
670
697
|
async seeDeviceIsUnlocked() {
|
|
671
|
-
onlyForApps.call(this, supportedPlatform.android)
|
|
672
|
-
const res = await this.browser.isLocked()
|
|
673
|
-
return truth('device', 'to be locked').negate(res)
|
|
698
|
+
onlyForApps.call(this, supportedPlatform.android)
|
|
699
|
+
const res = await this.browser.isLocked()
|
|
700
|
+
return truth('device', 'to be locked').negate(res)
|
|
674
701
|
}
|
|
675
702
|
|
|
676
703
|
/**
|
|
@@ -688,15 +715,15 @@ class Appium extends Webdriver {
|
|
|
688
715
|
* Appium: support Android and iOS
|
|
689
716
|
*/
|
|
690
717
|
async seeOrientationIs(orientation) {
|
|
691
|
-
onlyForApps.call(this)
|
|
718
|
+
onlyForApps.call(this)
|
|
692
719
|
|
|
693
720
|
const res = await this.axios({
|
|
694
721
|
method: 'get',
|
|
695
|
-
url: `${this._buildAppiumEndpoint()}/
|
|
696
|
-
})
|
|
722
|
+
url: `${this._buildAppiumEndpoint()}/orientation`,
|
|
723
|
+
})
|
|
697
724
|
|
|
698
|
-
const currentOrientation = res.data.value
|
|
699
|
-
return truth('orientation', `to be ${orientation}`).assert(currentOrientation === orientation)
|
|
725
|
+
const currentOrientation = res.data.value
|
|
726
|
+
return truth('orientation', `to be ${orientation}`).assert(currentOrientation === orientation)
|
|
700
727
|
}
|
|
701
728
|
|
|
702
729
|
/**
|
|
@@ -712,13 +739,13 @@ class Appium extends Webdriver {
|
|
|
712
739
|
* Appium: support Android and iOS
|
|
713
740
|
*/
|
|
714
741
|
async setOrientation(orientation) {
|
|
715
|
-
onlyForApps.call(this)
|
|
742
|
+
onlyForApps.call(this)
|
|
716
743
|
|
|
717
744
|
return this.axios({
|
|
718
745
|
method: 'post',
|
|
719
|
-
url: `${this._buildAppiumEndpoint()}/
|
|
746
|
+
url: `${this._buildAppiumEndpoint()}/orientation`,
|
|
720
747
|
data: { orientation },
|
|
721
|
-
})
|
|
748
|
+
})
|
|
722
749
|
}
|
|
723
750
|
|
|
724
751
|
/**
|
|
@@ -733,8 +760,8 @@ class Appium extends Webdriver {
|
|
|
733
760
|
* Appium: support Android and iOS
|
|
734
761
|
*/
|
|
735
762
|
async grabAllContexts() {
|
|
736
|
-
onlyForApps.call(this)
|
|
737
|
-
return this.browser.getContexts()
|
|
763
|
+
onlyForApps.call(this)
|
|
764
|
+
return this.browser.getContexts()
|
|
738
765
|
}
|
|
739
766
|
|
|
740
767
|
/**
|
|
@@ -749,8 +776,8 @@ class Appium extends Webdriver {
|
|
|
749
776
|
* Appium: support Android and iOS
|
|
750
777
|
*/
|
|
751
778
|
async grabContext() {
|
|
752
|
-
onlyForApps.call(this)
|
|
753
|
-
return this.browser.getContext()
|
|
779
|
+
onlyForApps.call(this)
|
|
780
|
+
return this.browser.getContext()
|
|
754
781
|
}
|
|
755
782
|
|
|
756
783
|
/**
|
|
@@ -765,8 +792,8 @@ class Appium extends Webdriver {
|
|
|
765
792
|
* Appium: support only Android
|
|
766
793
|
*/
|
|
767
794
|
async grabCurrentActivity() {
|
|
768
|
-
onlyForApps.call(this, supportedPlatform.android)
|
|
769
|
-
return this.browser.getCurrentActivity()
|
|
795
|
+
onlyForApps.call(this, supportedPlatform.android)
|
|
796
|
+
return this.browser.getCurrentActivity()
|
|
770
797
|
}
|
|
771
798
|
|
|
772
799
|
/**
|
|
@@ -783,14 +810,14 @@ class Appium extends Webdriver {
|
|
|
783
810
|
* Appium: support only Android
|
|
784
811
|
*/
|
|
785
812
|
async grabNetworkConnection() {
|
|
786
|
-
onlyForApps.call(this, supportedPlatform.android)
|
|
787
|
-
const res = await this.browser.getNetworkConnection()
|
|
813
|
+
onlyForApps.call(this, supportedPlatform.android)
|
|
814
|
+
const res = await this.browser.getNetworkConnection()
|
|
788
815
|
return {
|
|
789
816
|
value: res,
|
|
790
817
|
inAirplaneMode: res.inAirplaneMode,
|
|
791
818
|
hasWifi: res.hasWifi,
|
|
792
819
|
hasData: res.hasData,
|
|
793
|
-
}
|
|
820
|
+
}
|
|
794
821
|
}
|
|
795
822
|
|
|
796
823
|
/**
|
|
@@ -805,10 +832,10 @@ class Appium extends Webdriver {
|
|
|
805
832
|
* Appium: support Android and iOS
|
|
806
833
|
*/
|
|
807
834
|
async grabOrientation() {
|
|
808
|
-
onlyForApps.call(this)
|
|
809
|
-
const res = await this.browser.orientation()
|
|
810
|
-
this.debugSection('Orientation', res)
|
|
811
|
-
return res
|
|
835
|
+
onlyForApps.call(this)
|
|
836
|
+
const res = await this.browser.orientation()
|
|
837
|
+
this.debugSection('Orientation', res)
|
|
838
|
+
return res
|
|
812
839
|
}
|
|
813
840
|
|
|
814
841
|
/**
|
|
@@ -823,10 +850,10 @@ class Appium extends Webdriver {
|
|
|
823
850
|
* Appium: support Android and iOS
|
|
824
851
|
*/
|
|
825
852
|
async grabSettings() {
|
|
826
|
-
onlyForApps.call(this)
|
|
827
|
-
const res = await this.browser.getSettings()
|
|
828
|
-
this.debugSection('Settings', JSON.stringify(res))
|
|
829
|
-
return res
|
|
853
|
+
onlyForApps.call(this)
|
|
854
|
+
const res = await this.browser.getSettings()
|
|
855
|
+
this.debugSection('Settings', JSON.stringify(res))
|
|
856
|
+
return res
|
|
830
857
|
}
|
|
831
858
|
|
|
832
859
|
/**
|
|
@@ -835,7 +862,7 @@ class Appium extends Webdriver {
|
|
|
835
862
|
* @param {*} context the context to switch to
|
|
836
863
|
*/
|
|
837
864
|
async switchToContext(context) {
|
|
838
|
-
return this.browser.switchContext(context)
|
|
865
|
+
return this.browser.switchContext(context)
|
|
839
866
|
}
|
|
840
867
|
|
|
841
868
|
/**
|
|
@@ -855,17 +882,17 @@ class Appium extends Webdriver {
|
|
|
855
882
|
* @param {string} [context]
|
|
856
883
|
*/
|
|
857
884
|
async switchToWeb(context) {
|
|
858
|
-
this.isWeb = true
|
|
859
|
-
this.defaultContext = 'body'
|
|
885
|
+
this.isWeb = true
|
|
886
|
+
this.defaultContext = 'body'
|
|
860
887
|
|
|
861
|
-
if (context) return this.switchToContext(context)
|
|
862
|
-
const contexts = await this.grabAllContexts()
|
|
863
|
-
this.debugSection('Contexts', contexts.toString())
|
|
888
|
+
if (context) return this.switchToContext(context)
|
|
889
|
+
const contexts = await this.grabAllContexts()
|
|
890
|
+
this.debugSection('Contexts', contexts.toString())
|
|
864
891
|
for (const idx in contexts) {
|
|
865
|
-
if (contexts[idx].match(/^WEBVIEW/)) return this.switchToContext(contexts[idx])
|
|
892
|
+
if (contexts[idx].match(/^WEBVIEW/)) return this.switchToContext(contexts[idx])
|
|
866
893
|
}
|
|
867
894
|
|
|
868
|
-
throw new Error('No WEBVIEW could be guessed, please specify one in params')
|
|
895
|
+
throw new Error('No WEBVIEW could be guessed, please specify one in params')
|
|
869
896
|
}
|
|
870
897
|
|
|
871
898
|
/**
|
|
@@ -882,11 +909,11 @@ class Appium extends Webdriver {
|
|
|
882
909
|
* @return {Promise<void>}
|
|
883
910
|
*/
|
|
884
911
|
async switchToNative(context = null) {
|
|
885
|
-
this.isWeb = false
|
|
886
|
-
this.defaultContext = '//*'
|
|
912
|
+
this.isWeb = false
|
|
913
|
+
this.defaultContext = '//*'
|
|
887
914
|
|
|
888
|
-
if (context) return this.switchToContext(context)
|
|
889
|
-
return this.switchToContext('NATIVE_APP')
|
|
915
|
+
if (context) return this.switchToContext(context)
|
|
916
|
+
return this.switchToContext('NATIVE_APP')
|
|
890
917
|
}
|
|
891
918
|
|
|
892
919
|
/**
|
|
@@ -903,8 +930,8 @@ class Appium extends Webdriver {
|
|
|
903
930
|
* @return {Promise<void>}
|
|
904
931
|
*/
|
|
905
932
|
async startActivity(appPackage, appActivity) {
|
|
906
|
-
onlyForApps.call(this, supportedPlatform.android)
|
|
907
|
-
return this.browser.startActivity(appPackage, appActivity)
|
|
933
|
+
onlyForApps.call(this, supportedPlatform.android)
|
|
934
|
+
return this.browser.startActivity(appPackage, appActivity)
|
|
908
935
|
}
|
|
909
936
|
|
|
910
937
|
/**
|
|
@@ -929,8 +956,8 @@ class Appium extends Webdriver {
|
|
|
929
956
|
* @return {Promise<number>}
|
|
930
957
|
*/
|
|
931
958
|
async setNetworkConnection(value) {
|
|
932
|
-
onlyForApps.call(this, supportedPlatform.android)
|
|
933
|
-
return this.browser.setNetworkConnection(value)
|
|
959
|
+
onlyForApps.call(this, supportedPlatform.android)
|
|
960
|
+
return this.browser.setNetworkConnection(value)
|
|
934
961
|
}
|
|
935
962
|
|
|
936
963
|
/**
|
|
@@ -945,8 +972,8 @@ class Appium extends Webdriver {
|
|
|
945
972
|
* Appium: support Android and iOS
|
|
946
973
|
*/
|
|
947
974
|
async setSettings(settings) {
|
|
948
|
-
onlyForApps.call(this)
|
|
949
|
-
return this.browser.settings(settings)
|
|
975
|
+
onlyForApps.call(this)
|
|
976
|
+
return this.browser.settings(settings)
|
|
950
977
|
}
|
|
951
978
|
|
|
952
979
|
/**
|
|
@@ -955,21 +982,19 @@ class Appium extends Webdriver {
|
|
|
955
982
|
* ```js
|
|
956
983
|
* // taps outside to hide keyboard per default
|
|
957
984
|
* I.hideDeviceKeyboard();
|
|
958
|
-
* I.hideDeviceKeyboard('tapOutside');
|
|
959
|
-
*
|
|
960
|
-
* // or by pressing key
|
|
961
|
-
* I.hideDeviceKeyboard('pressKey', 'Done');
|
|
962
985
|
* ```
|
|
963
986
|
*
|
|
964
987
|
* Appium: support Android and iOS
|
|
965
988
|
*
|
|
966
|
-
* @param {'tapOutside' | 'pressKey'} [strategy] Desired strategy to close keyboard (‘tapOutside’ or ‘pressKey’)
|
|
967
|
-
* @param {string} [key] Optional key
|
|
968
989
|
*/
|
|
969
|
-
async hideDeviceKeyboard(
|
|
970
|
-
onlyForApps.call(this)
|
|
971
|
-
|
|
972
|
-
return this.
|
|
990
|
+
async hideDeviceKeyboard() {
|
|
991
|
+
onlyForApps.call(this)
|
|
992
|
+
|
|
993
|
+
return this.axios({
|
|
994
|
+
method: 'post',
|
|
995
|
+
url: `${this._buildAppiumEndpoint()}/appium/device/hide_keyboard`,
|
|
996
|
+
data: {},
|
|
997
|
+
})
|
|
973
998
|
}
|
|
974
999
|
|
|
975
1000
|
/**
|
|
@@ -986,8 +1011,8 @@ class Appium extends Webdriver {
|
|
|
986
1011
|
* Appium: support only Android
|
|
987
1012
|
*/
|
|
988
1013
|
async sendDeviceKeyEvent(keyValue) {
|
|
989
|
-
onlyForApps.call(this, supportedPlatform.android)
|
|
990
|
-
return this.browser.pressKeyCode(keyValue)
|
|
1014
|
+
onlyForApps.call(this, supportedPlatform.android)
|
|
1015
|
+
return this.browser.pressKeyCode(keyValue)
|
|
991
1016
|
}
|
|
992
1017
|
|
|
993
1018
|
/**
|
|
@@ -1002,8 +1027,8 @@ class Appium extends Webdriver {
|
|
|
1002
1027
|
* Appium: support only Android
|
|
1003
1028
|
*/
|
|
1004
1029
|
async openNotifications() {
|
|
1005
|
-
onlyForApps.call(this, supportedPlatform.android)
|
|
1006
|
-
return this.browser.openNotifications()
|
|
1030
|
+
onlyForApps.call(this, supportedPlatform.android)
|
|
1031
|
+
return this.browser.openNotifications()
|
|
1007
1032
|
}
|
|
1008
1033
|
|
|
1009
1034
|
/**
|
|
@@ -1022,13 +1047,13 @@ class Appium extends Webdriver {
|
|
|
1022
1047
|
* Appium: support Android and iOS
|
|
1023
1048
|
*/
|
|
1024
1049
|
async makeTouchAction(locator, action) {
|
|
1025
|
-
onlyForApps.call(this)
|
|
1026
|
-
const element = await this.browser.$(parseLocator.call(this, locator))
|
|
1050
|
+
onlyForApps.call(this)
|
|
1051
|
+
const element = await this.browser.$(parseLocator.call(this, locator))
|
|
1027
1052
|
|
|
1028
1053
|
return this.browser.touchAction({
|
|
1029
1054
|
action,
|
|
1030
1055
|
element,
|
|
1031
|
-
})
|
|
1056
|
+
})
|
|
1032
1057
|
}
|
|
1033
1058
|
|
|
1034
1059
|
/**
|
|
@@ -1045,7 +1070,13 @@ class Appium extends Webdriver {
|
|
|
1045
1070
|
* @param {*} locator
|
|
1046
1071
|
*/
|
|
1047
1072
|
async tap(locator) {
|
|
1048
|
-
|
|
1073
|
+
const { elementId } = await this.browser.$(parseLocator.call(this, locator))
|
|
1074
|
+
|
|
1075
|
+
return this.axios({
|
|
1076
|
+
method: 'post',
|
|
1077
|
+
url: `${this._buildAppiumEndpoint()}/element/${elementId}/click`,
|
|
1078
|
+
data: {},
|
|
1079
|
+
})
|
|
1049
1080
|
}
|
|
1050
1081
|
|
|
1051
1082
|
/**
|
|
@@ -1066,14 +1097,16 @@ class Appium extends Webdriver {
|
|
|
1066
1097
|
*
|
|
1067
1098
|
* Appium: support Android and iOS
|
|
1068
1099
|
*/
|
|
1069
|
-
|
|
1100
|
+
|
|
1070
1101
|
async swipe(locator, xoffset, yoffset, speed = 1000) {
|
|
1071
|
-
onlyForApps.call(this)
|
|
1072
|
-
const res = await this.browser.$(parseLocator.call(this, locator))
|
|
1102
|
+
onlyForApps.call(this)
|
|
1103
|
+
const res = await this.browser.$(parseLocator.call(this, locator))
|
|
1073
1104
|
// if (!res.length) throw new ElementNotFound(locator, 'was not found in UI');
|
|
1074
|
-
return this.performSwipe(await res.getLocation(), {
|
|
1105
|
+
return this.performSwipe(await res.getLocation(), {
|
|
1106
|
+
x: (await res.getLocation()).x + xoffset,
|
|
1107
|
+
y: (await res.getLocation()).y + yoffset,
|
|
1108
|
+
})
|
|
1075
1109
|
}
|
|
1076
|
-
/* eslint-enable */
|
|
1077
1110
|
|
|
1078
1111
|
/**
|
|
1079
1112
|
* Perform a swipe on the screen.
|
|
@@ -1088,42 +1121,44 @@ class Appium extends Webdriver {
|
|
|
1088
1121
|
* Appium: support Android and iOS
|
|
1089
1122
|
*/
|
|
1090
1123
|
async performSwipe(from, to) {
|
|
1091
|
-
await this.browser.performActions([
|
|
1092
|
-
|
|
1093
|
-
|
|
1094
|
-
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
actions: [
|
|
1098
|
-
{
|
|
1099
|
-
duration: 0,
|
|
1100
|
-
x: from.x,
|
|
1101
|
-
y: from.y,
|
|
1102
|
-
type: 'pointerMove',
|
|
1103
|
-
origin: 'viewport',
|
|
1104
|
-
},
|
|
1105
|
-
{
|
|
1106
|
-
button: 1,
|
|
1107
|
-
type: 'pointerDown',
|
|
1108
|
-
},
|
|
1109
|
-
{
|
|
1110
|
-
duration: 200,
|
|
1111
|
-
type: 'pause',
|
|
1112
|
-
},
|
|
1113
|
-
{
|
|
1114
|
-
duration: 600,
|
|
1115
|
-
x: to.x,
|
|
1116
|
-
y: to.y,
|
|
1117
|
-
type: 'pointerMove',
|
|
1118
|
-
origin: 'viewport',
|
|
1124
|
+
await this.browser.performActions([
|
|
1125
|
+
{
|
|
1126
|
+
id: uuidv4(),
|
|
1127
|
+
type: 'pointer',
|
|
1128
|
+
parameters: {
|
|
1129
|
+
pointerType: 'touch',
|
|
1119
1130
|
},
|
|
1120
|
-
|
|
1121
|
-
|
|
1122
|
-
|
|
1123
|
-
|
|
1124
|
-
|
|
1125
|
-
|
|
1126
|
-
|
|
1131
|
+
actions: [
|
|
1132
|
+
{
|
|
1133
|
+
duration: 0,
|
|
1134
|
+
x: from.x,
|
|
1135
|
+
y: from.y,
|
|
1136
|
+
type: 'pointerMove',
|
|
1137
|
+
origin: 'viewport',
|
|
1138
|
+
},
|
|
1139
|
+
{
|
|
1140
|
+
button: 1,
|
|
1141
|
+
type: 'pointerDown',
|
|
1142
|
+
},
|
|
1143
|
+
{
|
|
1144
|
+
duration: 200,
|
|
1145
|
+
type: 'pause',
|
|
1146
|
+
},
|
|
1147
|
+
{
|
|
1148
|
+
duration: 600,
|
|
1149
|
+
x: to.x,
|
|
1150
|
+
y: to.y,
|
|
1151
|
+
type: 'pointerMove',
|
|
1152
|
+
origin: 'viewport',
|
|
1153
|
+
},
|
|
1154
|
+
{
|
|
1155
|
+
button: 1,
|
|
1156
|
+
type: 'pointerUp',
|
|
1157
|
+
},
|
|
1158
|
+
],
|
|
1159
|
+
},
|
|
1160
|
+
])
|
|
1161
|
+
await this.browser.pause(2000)
|
|
1127
1162
|
}
|
|
1128
1163
|
|
|
1129
1164
|
/**
|
|
@@ -1144,14 +1179,14 @@ class Appium extends Webdriver {
|
|
|
1144
1179
|
* Appium: support Android and iOS
|
|
1145
1180
|
*/
|
|
1146
1181
|
async swipeDown(locator, yoffset = 1000, speed) {
|
|
1147
|
-
onlyForApps.call(this)
|
|
1182
|
+
onlyForApps.call(this)
|
|
1148
1183
|
|
|
1149
1184
|
if (!speed) {
|
|
1150
|
-
speed = yoffset
|
|
1151
|
-
yoffset = 100
|
|
1185
|
+
speed = yoffset
|
|
1186
|
+
yoffset = 100
|
|
1152
1187
|
}
|
|
1153
1188
|
|
|
1154
|
-
return this.swipe(parseLocator.call(this, locator), 0, yoffset, speed)
|
|
1189
|
+
return this.swipe(parseLocator.call(this, locator), 0, yoffset, speed)
|
|
1155
1190
|
}
|
|
1156
1191
|
|
|
1157
1192
|
/**
|
|
@@ -1173,13 +1208,13 @@ class Appium extends Webdriver {
|
|
|
1173
1208
|
* Appium: support Android and iOS
|
|
1174
1209
|
*/
|
|
1175
1210
|
async swipeLeft(locator, xoffset = 1000, speed) {
|
|
1176
|
-
onlyForApps.call(this)
|
|
1211
|
+
onlyForApps.call(this)
|
|
1177
1212
|
if (!speed) {
|
|
1178
|
-
speed = xoffset
|
|
1179
|
-
xoffset = 100
|
|
1213
|
+
speed = xoffset
|
|
1214
|
+
xoffset = 100
|
|
1180
1215
|
}
|
|
1181
1216
|
|
|
1182
|
-
return this.swipe(parseLocator.call(this, locator), -xoffset, 0, speed)
|
|
1217
|
+
return this.swipe(parseLocator.call(this, locator), -xoffset, 0, speed)
|
|
1183
1218
|
}
|
|
1184
1219
|
|
|
1185
1220
|
/**
|
|
@@ -1200,13 +1235,13 @@ class Appium extends Webdriver {
|
|
|
1200
1235
|
* Appium: support Android and iOS
|
|
1201
1236
|
*/
|
|
1202
1237
|
async swipeRight(locator, xoffset = 1000, speed) {
|
|
1203
|
-
onlyForApps.call(this)
|
|
1238
|
+
onlyForApps.call(this)
|
|
1204
1239
|
if (!speed) {
|
|
1205
|
-
speed = xoffset
|
|
1206
|
-
xoffset = 100
|
|
1240
|
+
speed = xoffset
|
|
1241
|
+
xoffset = 100
|
|
1207
1242
|
}
|
|
1208
1243
|
|
|
1209
|
-
return this.swipe(parseLocator.call(this, locator), xoffset, 0, speed)
|
|
1244
|
+
return this.swipe(parseLocator.call(this, locator), xoffset, 0, speed)
|
|
1210
1245
|
}
|
|
1211
1246
|
|
|
1212
1247
|
/**
|
|
@@ -1227,14 +1262,14 @@ class Appium extends Webdriver {
|
|
|
1227
1262
|
* Appium: support Android and iOS
|
|
1228
1263
|
*/
|
|
1229
1264
|
async swipeUp(locator, yoffset = 1000, speed) {
|
|
1230
|
-
onlyForApps.call(this)
|
|
1265
|
+
onlyForApps.call(this)
|
|
1231
1266
|
|
|
1232
1267
|
if (!speed) {
|
|
1233
|
-
speed = yoffset
|
|
1234
|
-
yoffset = 100
|
|
1268
|
+
speed = yoffset
|
|
1269
|
+
yoffset = 100
|
|
1235
1270
|
}
|
|
1236
1271
|
|
|
1237
|
-
return this.swipe(parseLocator.call(this, locator), 0, -yoffset, speed)
|
|
1272
|
+
return this.swipe(parseLocator.call(this, locator), 0, -yoffset, speed)
|
|
1238
1273
|
}
|
|
1239
1274
|
|
|
1240
1275
|
/**
|
|
@@ -1261,55 +1296,61 @@ class Appium extends Webdriver {
|
|
|
1261
1296
|
* Appium: support Android and iOS
|
|
1262
1297
|
*/
|
|
1263
1298
|
async swipeTo(searchableLocator, scrollLocator, direction, timeout, offset, speed) {
|
|
1264
|
-
onlyForApps.call(this)
|
|
1265
|
-
direction = direction || 'down'
|
|
1299
|
+
onlyForApps.call(this)
|
|
1300
|
+
direction = direction || 'down'
|
|
1266
1301
|
switch (direction) {
|
|
1267
1302
|
case 'down':
|
|
1268
|
-
direction = 'swipeDown'
|
|
1269
|
-
break
|
|
1303
|
+
direction = 'swipeDown'
|
|
1304
|
+
break
|
|
1270
1305
|
case 'up':
|
|
1271
|
-
direction = 'swipeUp'
|
|
1272
|
-
break
|
|
1306
|
+
direction = 'swipeUp'
|
|
1307
|
+
break
|
|
1273
1308
|
case 'left':
|
|
1274
|
-
direction = 'swipeLeft'
|
|
1275
|
-
break
|
|
1309
|
+
direction = 'swipeLeft'
|
|
1310
|
+
break
|
|
1276
1311
|
case 'right':
|
|
1277
|
-
direction = 'swipeRight'
|
|
1278
|
-
break
|
|
1312
|
+
direction = 'swipeRight'
|
|
1313
|
+
break
|
|
1279
1314
|
}
|
|
1280
|
-
timeout = timeout || this.options.waitForTimeoutInSeconds
|
|
1281
|
-
|
|
1282
|
-
const errorMsg = `element ("${searchableLocator}") still not visible after ${timeout}seconds
|
|
1283
|
-
const browser = this.browser
|
|
1284
|
-
let err = false
|
|
1285
|
-
let currentSource
|
|
1286
|
-
return browser
|
|
1287
|
-
|
|
1288
|
-
|
|
1289
|
-
|
|
1290
|
-
|
|
1291
|
-
.then(els => els.length && els[0].isDisplayed())
|
|
1292
|
-
.then((res) => {
|
|
1293
|
-
if (res) {
|
|
1294
|
-
return true;
|
|
1315
|
+
timeout = timeout || this.options.waitForTimeoutInSeconds
|
|
1316
|
+
|
|
1317
|
+
const errorMsg = `element ("${searchableLocator}") still not visible after ${timeout}seconds`
|
|
1318
|
+
const browser = this.browser
|
|
1319
|
+
let err = false
|
|
1320
|
+
let currentSource
|
|
1321
|
+
return browser
|
|
1322
|
+
.waitUntil(
|
|
1323
|
+
async () => {
|
|
1324
|
+
if (err) {
|
|
1325
|
+
return new Error(`Scroll to the end and element ${searchableLocator} was not found`)
|
|
1295
1326
|
}
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
return false;
|
|
1327
|
+
const els = await browser.$$(parseLocator.call(this, searchableLocator))
|
|
1328
|
+
if (els.length) {
|
|
1329
|
+
const displayed = await this._isDisplayedSafe(els[0])
|
|
1330
|
+
if (displayed) {
|
|
1331
|
+
return true
|
|
1302
1332
|
}
|
|
1303
|
-
}
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1333
|
+
}
|
|
1334
|
+
|
|
1335
|
+
await this[direction](scrollLocator, offset, speed)
|
|
1336
|
+
const source = await this.browser.getPageSource()
|
|
1337
|
+
if (source === currentSource) {
|
|
1338
|
+
err = true
|
|
1339
|
+
} else {
|
|
1340
|
+
currentSource = source
|
|
1341
|
+
return false
|
|
1342
|
+
}
|
|
1343
|
+
},
|
|
1344
|
+
timeout * 1000,
|
|
1345
|
+
errorMsg,
|
|
1346
|
+
)
|
|
1347
|
+
.catch(e => {
|
|
1307
1348
|
if (e.message.indexOf('timeout') && e.type !== 'NoSuchElement') {
|
|
1308
|
-
throw new AssertionFailedError({ customMessage: `Scroll to the end and element ${searchableLocator} was not found` }, '')
|
|
1349
|
+
throw new AssertionFailedError({ customMessage: `Scroll to the end and element ${searchableLocator} was not found` }, '')
|
|
1309
1350
|
} else {
|
|
1310
|
-
throw e
|
|
1351
|
+
throw e
|
|
1311
1352
|
}
|
|
1312
|
-
})
|
|
1353
|
+
})
|
|
1313
1354
|
}
|
|
1314
1355
|
|
|
1315
1356
|
/**
|
|
@@ -1341,8 +1382,8 @@ class Appium extends Webdriver {
|
|
|
1341
1382
|
* @param {Array} actions Array of touch actions
|
|
1342
1383
|
*/
|
|
1343
1384
|
async touchPerform(actions) {
|
|
1344
|
-
onlyForApps.call(this)
|
|
1345
|
-
return this.browser.touchPerform(actions)
|
|
1385
|
+
onlyForApps.call(this)
|
|
1386
|
+
return this.browser.touchPerform(actions)
|
|
1346
1387
|
}
|
|
1347
1388
|
|
|
1348
1389
|
/**
|
|
@@ -1361,13 +1402,15 @@ class Appium extends Webdriver {
|
|
|
1361
1402
|
* Appium: support Android and iOS
|
|
1362
1403
|
*/
|
|
1363
1404
|
async pullFile(path, dest) {
|
|
1364
|
-
onlyForApps.call(this)
|
|
1365
|
-
return this.browser.pullFile(path).then(res =>
|
|
1366
|
-
|
|
1367
|
-
|
|
1368
|
-
|
|
1369
|
-
|
|
1370
|
-
|
|
1405
|
+
onlyForApps.call(this)
|
|
1406
|
+
return this.browser.pullFile(path).then(res =>
|
|
1407
|
+
fs.writeFile(dest, Buffer.from(res, 'base64'), err => {
|
|
1408
|
+
if (err) {
|
|
1409
|
+
return false
|
|
1410
|
+
}
|
|
1411
|
+
return true
|
|
1412
|
+
}),
|
|
1413
|
+
)
|
|
1371
1414
|
}
|
|
1372
1415
|
|
|
1373
1416
|
/**
|
|
@@ -1382,8 +1425,8 @@ class Appium extends Webdriver {
|
|
|
1382
1425
|
* Appium: support only iOS
|
|
1383
1426
|
*/
|
|
1384
1427
|
async shakeDevice() {
|
|
1385
|
-
onlyForApps.call(this, 'iOS')
|
|
1386
|
-
return this.browser.shake()
|
|
1428
|
+
onlyForApps.call(this, 'iOS')
|
|
1429
|
+
return this.browser.shake()
|
|
1387
1430
|
}
|
|
1388
1431
|
|
|
1389
1432
|
/**
|
|
@@ -1400,8 +1443,8 @@ class Appium extends Webdriver {
|
|
|
1400
1443
|
* Appium: support only iOS
|
|
1401
1444
|
*/
|
|
1402
1445
|
async rotate(x, y, duration, radius, rotation, touchCount) {
|
|
1403
|
-
onlyForApps.call(this, 'iOS')
|
|
1404
|
-
return this.browser.rotate(x, y, duration, radius, rotation, touchCount)
|
|
1446
|
+
onlyForApps.call(this, 'iOS')
|
|
1447
|
+
return this.browser.rotate(x, y, duration, radius, rotation, touchCount)
|
|
1405
1448
|
}
|
|
1406
1449
|
|
|
1407
1450
|
/**
|
|
@@ -1414,8 +1457,8 @@ class Appium extends Webdriver {
|
|
|
1414
1457
|
* Appium: support only iOS
|
|
1415
1458
|
*/
|
|
1416
1459
|
async setImmediateValue(id, value) {
|
|
1417
|
-
onlyForApps.call(this, 'iOS')
|
|
1418
|
-
return this.browser.setImmediateValue(id, value)
|
|
1460
|
+
onlyForApps.call(this, 'iOS')
|
|
1461
|
+
return this.browser.setImmediateValue(id, value)
|
|
1419
1462
|
}
|
|
1420
1463
|
|
|
1421
1464
|
/**
|
|
@@ -1433,9 +1476,9 @@ class Appium extends Webdriver {
|
|
|
1433
1476
|
* TODO: not tested
|
|
1434
1477
|
*/
|
|
1435
1478
|
async simulateTouchId(match) {
|
|
1436
|
-
onlyForApps.call(this, 'iOS')
|
|
1437
|
-
match = match || true
|
|
1438
|
-
return this.browser.touchId(match)
|
|
1479
|
+
onlyForApps.call(this, 'iOS')
|
|
1480
|
+
match = match || true
|
|
1481
|
+
return this.browser.touchId(match)
|
|
1439
1482
|
}
|
|
1440
1483
|
|
|
1441
1484
|
/**
|
|
@@ -1450,8 +1493,8 @@ class Appium extends Webdriver {
|
|
|
1450
1493
|
* Appium: support both Android and iOS
|
|
1451
1494
|
*/
|
|
1452
1495
|
async closeApp() {
|
|
1453
|
-
onlyForApps.call(this)
|
|
1454
|
-
return this.browser.closeApp()
|
|
1496
|
+
onlyForApps.call(this)
|
|
1497
|
+
return this.browser.closeApp()
|
|
1455
1498
|
}
|
|
1456
1499
|
|
|
1457
1500
|
/**
|
|
@@ -1459,8 +1502,8 @@ class Appium extends Webdriver {
|
|
|
1459
1502
|
*
|
|
1460
1503
|
*/
|
|
1461
1504
|
async appendField(field, value) {
|
|
1462
|
-
if (this.isWeb) return super.appendField(field, value)
|
|
1463
|
-
return super.appendField(parseLocator.call(this, field), value)
|
|
1505
|
+
if (this.isWeb) return super.appendField(field, value)
|
|
1506
|
+
return super.appendField(parseLocator.call(this, field), value)
|
|
1464
1507
|
}
|
|
1465
1508
|
|
|
1466
1509
|
/**
|
|
@@ -1468,8 +1511,8 @@ class Appium extends Webdriver {
|
|
|
1468
1511
|
*
|
|
1469
1512
|
*/
|
|
1470
1513
|
async checkOption(field) {
|
|
1471
|
-
if (this.isWeb) return super.checkOption(field)
|
|
1472
|
-
return super.checkOption(parseLocator.call(this, field))
|
|
1514
|
+
if (this.isWeb) return super.checkOption(field)
|
|
1515
|
+
return super.checkOption(parseLocator.call(this, field))
|
|
1473
1516
|
}
|
|
1474
1517
|
|
|
1475
1518
|
/**
|
|
@@ -1477,8 +1520,15 @@ class Appium extends Webdriver {
|
|
|
1477
1520
|
*
|
|
1478
1521
|
*/
|
|
1479
1522
|
async click(locator, context) {
|
|
1480
|
-
if (this.isWeb) return super.click(locator, context)
|
|
1481
|
-
|
|
1523
|
+
if (this.isWeb) return super.click(locator, context)
|
|
1524
|
+
|
|
1525
|
+
const { elementId } = await this.browser.$(parseLocator.call(this, locator), parseLocator.call(this, context))
|
|
1526
|
+
|
|
1527
|
+
return this.axios({
|
|
1528
|
+
method: 'post',
|
|
1529
|
+
url: `${this._buildAppiumEndpoint()}/element/${elementId}/click`,
|
|
1530
|
+
data: {},
|
|
1531
|
+
})
|
|
1482
1532
|
}
|
|
1483
1533
|
|
|
1484
1534
|
/**
|
|
@@ -1486,16 +1536,35 @@ class Appium extends Webdriver {
|
|
|
1486
1536
|
*
|
|
1487
1537
|
*/
|
|
1488
1538
|
async dontSeeCheckboxIsChecked(field) {
|
|
1489
|
-
if (this.isWeb) return super.dontSeeCheckboxIsChecked(field)
|
|
1490
|
-
return super.dontSeeCheckboxIsChecked(parseLocator.call(this, field))
|
|
1539
|
+
if (this.isWeb) return super.dontSeeCheckboxIsChecked(field)
|
|
1540
|
+
return super.dontSeeCheckboxIsChecked(parseLocator.call(this, field))
|
|
1491
1541
|
}
|
|
1492
1542
|
|
|
1493
1543
|
/**
|
|
1494
1544
|
* {{> dontSeeElement }}
|
|
1495
1545
|
*/
|
|
1496
1546
|
async dontSeeElement(locator) {
|
|
1497
|
-
if (this.isWeb) return super.dontSeeElement(locator)
|
|
1498
|
-
|
|
1547
|
+
if (this.isWeb) return super.dontSeeElement(locator)
|
|
1548
|
+
|
|
1549
|
+
// For mobile native apps, use safe isDisplayed wrapper
|
|
1550
|
+
const parsedLocator = parseLocator.call(this, locator)
|
|
1551
|
+
const res = await this._locate(parsedLocator, false)
|
|
1552
|
+
|
|
1553
|
+
if (!res || res.length === 0) {
|
|
1554
|
+
return truth(`elements of ${Locator.build(parsedLocator)}`, 'to be seen').negate(false)
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1557
|
+
const selected = []
|
|
1558
|
+
for (const el of res) {
|
|
1559
|
+
const displayed = await this._isDisplayedSafe(el)
|
|
1560
|
+
if (displayed) selected.push(true)
|
|
1561
|
+
}
|
|
1562
|
+
|
|
1563
|
+
try {
|
|
1564
|
+
return truth(`elements of ${Locator.build(parsedLocator)}`, 'to be seen').negate(selected)
|
|
1565
|
+
} catch (err) {
|
|
1566
|
+
throw err
|
|
1567
|
+
}
|
|
1499
1568
|
}
|
|
1500
1569
|
|
|
1501
1570
|
/**
|
|
@@ -1503,17 +1572,17 @@ class Appium extends Webdriver {
|
|
|
1503
1572
|
*
|
|
1504
1573
|
*/
|
|
1505
1574
|
async dontSeeInField(field, value) {
|
|
1506
|
-
const _value =
|
|
1507
|
-
if (this.isWeb) return super.dontSeeInField(field, _value)
|
|
1508
|
-
return super.dontSeeInField(parseLocator.call(this, field), _value)
|
|
1575
|
+
const _value = typeof value === 'boolean' ? value : value.toString()
|
|
1576
|
+
if (this.isWeb) return super.dontSeeInField(field, _value)
|
|
1577
|
+
return super.dontSeeInField(parseLocator.call(this, field), _value)
|
|
1509
1578
|
}
|
|
1510
1579
|
|
|
1511
1580
|
/**
|
|
1512
1581
|
* {{> dontSee }}
|
|
1513
1582
|
*/
|
|
1514
1583
|
async dontSee(text, context = null) {
|
|
1515
|
-
if (this.isWeb) return super.dontSee(text, context)
|
|
1516
|
-
return super.dontSee(text, parseLocator.call(this, context))
|
|
1584
|
+
if (this.isWeb) return super.dontSee(text, context)
|
|
1585
|
+
return super.dontSee(text, parseLocator.call(this, context))
|
|
1517
1586
|
}
|
|
1518
1587
|
|
|
1519
1588
|
/**
|
|
@@ -1521,9 +1590,9 @@ class Appium extends Webdriver {
|
|
|
1521
1590
|
*
|
|
1522
1591
|
*/
|
|
1523
1592
|
async fillField(field, value) {
|
|
1524
|
-
value = value.toString()
|
|
1525
|
-
if (this.isWeb) return super.fillField(field, value)
|
|
1526
|
-
return super.fillField(parseLocator.call(this, field), value)
|
|
1593
|
+
value = value.toString()
|
|
1594
|
+
if (this.isWeb) return super.fillField(field, value)
|
|
1595
|
+
return super.fillField(parseLocator.call(this, field), value)
|
|
1527
1596
|
}
|
|
1528
1597
|
|
|
1529
1598
|
/**
|
|
@@ -1531,8 +1600,8 @@ class Appium extends Webdriver {
|
|
|
1531
1600
|
*
|
|
1532
1601
|
*/
|
|
1533
1602
|
async grabTextFromAll(locator) {
|
|
1534
|
-
if (this.isWeb) return super.grabTextFromAll(locator)
|
|
1535
|
-
return super.grabTextFromAll(parseLocator.call(this, locator))
|
|
1603
|
+
if (this.isWeb) return super.grabTextFromAll(locator)
|
|
1604
|
+
return super.grabTextFromAll(parseLocator.call(this, locator))
|
|
1536
1605
|
}
|
|
1537
1606
|
|
|
1538
1607
|
/**
|
|
@@ -1540,16 +1609,27 @@ class Appium extends Webdriver {
|
|
|
1540
1609
|
*
|
|
1541
1610
|
*/
|
|
1542
1611
|
async grabTextFrom(locator) {
|
|
1543
|
-
if (this.isWeb) return super.grabTextFrom(locator)
|
|
1544
|
-
return super.grabTextFrom(parseLocator.call(this, locator))
|
|
1612
|
+
if (this.isWeb) return super.grabTextFrom(locator)
|
|
1613
|
+
return super.grabTextFrom(parseLocator.call(this, locator))
|
|
1545
1614
|
}
|
|
1546
1615
|
|
|
1547
1616
|
/**
|
|
1548
1617
|
* {{> grabNumberOfVisibleElements }}
|
|
1549
1618
|
*/
|
|
1550
1619
|
async grabNumberOfVisibleElements(locator) {
|
|
1551
|
-
if (this.isWeb) return super.grabNumberOfVisibleElements(locator)
|
|
1552
|
-
|
|
1620
|
+
if (this.isWeb) return super.grabNumberOfVisibleElements(locator)
|
|
1621
|
+
|
|
1622
|
+
// For mobile native apps, use safe isDisplayed wrapper
|
|
1623
|
+
const parsedLocator = parseLocator.call(this, locator)
|
|
1624
|
+
const res = await this._locate(parsedLocator)
|
|
1625
|
+
|
|
1626
|
+
const selected = []
|
|
1627
|
+
for (const el of res) {
|
|
1628
|
+
const displayed = await this._isDisplayedSafe(el)
|
|
1629
|
+
if (displayed) selected.push(true)
|
|
1630
|
+
}
|
|
1631
|
+
|
|
1632
|
+
return selected.length
|
|
1553
1633
|
}
|
|
1554
1634
|
|
|
1555
1635
|
/**
|
|
@@ -1558,8 +1638,8 @@ class Appium extends Webdriver {
|
|
|
1558
1638
|
* {{> grabAttributeFrom }}
|
|
1559
1639
|
*/
|
|
1560
1640
|
async grabAttributeFrom(locator, attr) {
|
|
1561
|
-
if (this.isWeb) return super.grabAttributeFrom(locator, attr)
|
|
1562
|
-
return super.grabAttributeFrom(parseLocator.call(this, locator), attr)
|
|
1641
|
+
if (this.isWeb) return super.grabAttributeFrom(locator, attr)
|
|
1642
|
+
return super.grabAttributeFrom(parseLocator.call(this, locator), attr)
|
|
1563
1643
|
}
|
|
1564
1644
|
|
|
1565
1645
|
/**
|
|
@@ -1567,8 +1647,8 @@ class Appium extends Webdriver {
|
|
|
1567
1647
|
* {{> grabAttributeFromAll }}
|
|
1568
1648
|
*/
|
|
1569
1649
|
async grabAttributeFromAll(locator, attr) {
|
|
1570
|
-
if (this.isWeb) return super.grabAttributeFromAll(locator, attr)
|
|
1571
|
-
return super.grabAttributeFromAll(parseLocator.call(this, locator), attr)
|
|
1650
|
+
if (this.isWeb) return super.grabAttributeFromAll(locator, attr)
|
|
1651
|
+
return super.grabAttributeFromAll(parseLocator.call(this, locator), attr)
|
|
1572
1652
|
}
|
|
1573
1653
|
|
|
1574
1654
|
/**
|
|
@@ -1576,8 +1656,8 @@ class Appium extends Webdriver {
|
|
|
1576
1656
|
*
|
|
1577
1657
|
*/
|
|
1578
1658
|
async grabValueFromAll(locator) {
|
|
1579
|
-
if (this.isWeb) return super.grabValueFromAll(locator)
|
|
1580
|
-
return super.grabValueFromAll(parseLocator.call(this, locator))
|
|
1659
|
+
if (this.isWeb) return super.grabValueFromAll(locator)
|
|
1660
|
+
return super.grabValueFromAll(parseLocator.call(this, locator))
|
|
1581
1661
|
}
|
|
1582
1662
|
|
|
1583
1663
|
/**
|
|
@@ -1585,8 +1665,8 @@ class Appium extends Webdriver {
|
|
|
1585
1665
|
*
|
|
1586
1666
|
*/
|
|
1587
1667
|
async grabValueFrom(locator) {
|
|
1588
|
-
if (this.isWeb) return super.grabValueFrom(locator)
|
|
1589
|
-
return super.grabValueFrom(parseLocator.call(this, locator))
|
|
1668
|
+
if (this.isWeb) return super.grabValueFrom(locator)
|
|
1669
|
+
return super.grabValueFrom(parseLocator.call(this, locator))
|
|
1590
1670
|
}
|
|
1591
1671
|
|
|
1592
1672
|
/**
|
|
@@ -1601,7 +1681,7 @@ class Appium extends Webdriver {
|
|
|
1601
1681
|
* @return {Promise<void>}
|
|
1602
1682
|
*/
|
|
1603
1683
|
async saveScreenshot(fileName) {
|
|
1604
|
-
return super.saveScreenshot(fileName, false)
|
|
1684
|
+
return super.saveScreenshot(fileName, false)
|
|
1605
1685
|
}
|
|
1606
1686
|
|
|
1607
1687
|
/**
|
|
@@ -1610,7 +1690,7 @@ class Appium extends Webdriver {
|
|
|
1610
1690
|
* Supported only for web testing
|
|
1611
1691
|
*/
|
|
1612
1692
|
async scrollIntoView(locator, scrollIntoViewOptions) {
|
|
1613
|
-
if (this.isWeb) return super.scrollIntoView(locator, scrollIntoViewOptions)
|
|
1693
|
+
if (this.isWeb) return super.scrollIntoView(locator, scrollIntoViewOptions)
|
|
1614
1694
|
}
|
|
1615
1695
|
|
|
1616
1696
|
/**
|
|
@@ -1618,8 +1698,8 @@ class Appium extends Webdriver {
|
|
|
1618
1698
|
*
|
|
1619
1699
|
*/
|
|
1620
1700
|
async seeCheckboxIsChecked(field) {
|
|
1621
|
-
if (this.isWeb) return super.seeCheckboxIsChecked(field)
|
|
1622
|
-
return super.seeCheckboxIsChecked(parseLocator.call(this, field))
|
|
1701
|
+
if (this.isWeb) return super.seeCheckboxIsChecked(field)
|
|
1702
|
+
return super.seeCheckboxIsChecked(parseLocator.call(this, field))
|
|
1623
1703
|
}
|
|
1624
1704
|
|
|
1625
1705
|
/**
|
|
@@ -1627,8 +1707,27 @@ class Appium extends Webdriver {
|
|
|
1627
1707
|
*
|
|
1628
1708
|
*/
|
|
1629
1709
|
async seeElement(locator) {
|
|
1630
|
-
if (this.isWeb) return super.seeElement(locator)
|
|
1631
|
-
|
|
1710
|
+
if (this.isWeb) return super.seeElement(locator)
|
|
1711
|
+
|
|
1712
|
+
// For mobile native apps, use safe isDisplayed wrapper
|
|
1713
|
+
const parsedLocator = parseLocator.call(this, locator)
|
|
1714
|
+
const res = await this._locate(parsedLocator, true)
|
|
1715
|
+
|
|
1716
|
+
if (!res || res.length === 0) {
|
|
1717
|
+
throw new ElementNotFound(parsedLocator)
|
|
1718
|
+
}
|
|
1719
|
+
|
|
1720
|
+
const selected = []
|
|
1721
|
+
for (const el of res) {
|
|
1722
|
+
const displayed = await this._isDisplayedSafe(el)
|
|
1723
|
+
if (displayed) selected.push(true)
|
|
1724
|
+
}
|
|
1725
|
+
|
|
1726
|
+
try {
|
|
1727
|
+
return truth(`elements of ${Locator.build(parsedLocator)}`, 'to be seen').assert(selected)
|
|
1728
|
+
} catch (e) {
|
|
1729
|
+
dontSeeElementError(parsedLocator)
|
|
1730
|
+
}
|
|
1632
1731
|
}
|
|
1633
1732
|
|
|
1634
1733
|
/**
|
|
@@ -1636,9 +1735,9 @@ class Appium extends Webdriver {
|
|
|
1636
1735
|
*
|
|
1637
1736
|
*/
|
|
1638
1737
|
async seeInField(field, value) {
|
|
1639
|
-
const _value =
|
|
1640
|
-
if (this.isWeb) return super.seeInField(field, _value)
|
|
1641
|
-
return super.seeInField(parseLocator.call(this, field), _value)
|
|
1738
|
+
const _value = typeof value === 'boolean' ? value : value.toString()
|
|
1739
|
+
if (this.isWeb) return super.seeInField(field, _value)
|
|
1740
|
+
return super.seeInField(parseLocator.call(this, field), _value)
|
|
1642
1741
|
}
|
|
1643
1742
|
|
|
1644
1743
|
/**
|
|
@@ -1646,8 +1745,8 @@ class Appium extends Webdriver {
|
|
|
1646
1745
|
*
|
|
1647
1746
|
*/
|
|
1648
1747
|
async see(text, context) {
|
|
1649
|
-
if (this.isWeb) return super.see(text, context)
|
|
1650
|
-
return super.see(text, parseLocator.call(this, context))
|
|
1748
|
+
if (this.isWeb) return super.see(text, context)
|
|
1749
|
+
return super.see(text, parseLocator.call(this, context))
|
|
1651
1750
|
}
|
|
1652
1751
|
|
|
1653
1752
|
/**
|
|
@@ -1656,8 +1755,8 @@ class Appium extends Webdriver {
|
|
|
1656
1755
|
* Supported only for web testing
|
|
1657
1756
|
*/
|
|
1658
1757
|
async selectOption(select, option) {
|
|
1659
|
-
if (this.isWeb) return super.selectOption(select, option)
|
|
1660
|
-
throw new Error(
|
|
1758
|
+
if (this.isWeb) return super.selectOption(select, option)
|
|
1759
|
+
throw new Error("Should be used only in Web context. In native context use 'click' method instead")
|
|
1661
1760
|
}
|
|
1662
1761
|
|
|
1663
1762
|
/**
|
|
@@ -1665,8 +1764,8 @@ class Appium extends Webdriver {
|
|
|
1665
1764
|
*
|
|
1666
1765
|
*/
|
|
1667
1766
|
async waitForElement(locator, sec = null) {
|
|
1668
|
-
if (this.isWeb) return super.waitForElement(locator, sec)
|
|
1669
|
-
return super.waitForElement(parseLocator.call(this, locator), sec)
|
|
1767
|
+
if (this.isWeb) return super.waitForElement(locator, sec)
|
|
1768
|
+
return super.waitForElement(parseLocator.call(this, locator), sec)
|
|
1670
1769
|
}
|
|
1671
1770
|
|
|
1672
1771
|
/**
|
|
@@ -1674,8 +1773,30 @@ class Appium extends Webdriver {
|
|
|
1674
1773
|
*
|
|
1675
1774
|
*/
|
|
1676
1775
|
async waitForVisible(locator, sec = null) {
|
|
1677
|
-
if (this.isWeb) return super.waitForVisible(locator, sec)
|
|
1678
|
-
|
|
1776
|
+
if (this.isWeb) return super.waitForVisible(locator, sec)
|
|
1777
|
+
|
|
1778
|
+
// For mobile native apps, use safe isDisplayed wrapper
|
|
1779
|
+
const parsedLocator = parseLocator.call(this, locator)
|
|
1780
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds
|
|
1781
|
+
|
|
1782
|
+
return this.browser.waitUntil(
|
|
1783
|
+
async () => {
|
|
1784
|
+
const res = await this._res(parsedLocator)
|
|
1785
|
+
if (!res || res.length === 0) return false
|
|
1786
|
+
|
|
1787
|
+
const selected = []
|
|
1788
|
+
for (const el of res) {
|
|
1789
|
+
const displayed = await this._isDisplayedSafe(el)
|
|
1790
|
+
if (displayed) selected.push(true)
|
|
1791
|
+
}
|
|
1792
|
+
|
|
1793
|
+
return selected.length > 0
|
|
1794
|
+
},
|
|
1795
|
+
{
|
|
1796
|
+
timeout: aSec * 1000,
|
|
1797
|
+
timeoutMsg: `element (${Locator.build(parsedLocator)}) still not visible after ${aSec} sec`,
|
|
1798
|
+
},
|
|
1799
|
+
)
|
|
1679
1800
|
}
|
|
1680
1801
|
|
|
1681
1802
|
/**
|
|
@@ -1683,8 +1804,27 @@ class Appium extends Webdriver {
|
|
|
1683
1804
|
*
|
|
1684
1805
|
*/
|
|
1685
1806
|
async waitForInvisible(locator, sec = null) {
|
|
1686
|
-
if (this.isWeb) return super.waitForInvisible(locator, sec)
|
|
1687
|
-
|
|
1807
|
+
if (this.isWeb) return super.waitForInvisible(locator, sec)
|
|
1808
|
+
|
|
1809
|
+
// For mobile native apps, use safe isDisplayed wrapper
|
|
1810
|
+
const parsedLocator = parseLocator.call(this, locator)
|
|
1811
|
+
const aSec = sec || this.options.waitForTimeoutInSeconds
|
|
1812
|
+
|
|
1813
|
+
return this.browser.waitUntil(
|
|
1814
|
+
async () => {
|
|
1815
|
+
const res = await this._res(parsedLocator)
|
|
1816
|
+
if (!res || res.length === 0) return true
|
|
1817
|
+
|
|
1818
|
+
const selected = []
|
|
1819
|
+
for (const el of res) {
|
|
1820
|
+
const displayed = await this._isDisplayedSafe(el)
|
|
1821
|
+
if (displayed) selected.push(true)
|
|
1822
|
+
}
|
|
1823
|
+
|
|
1824
|
+
return selected.length === 0
|
|
1825
|
+
},
|
|
1826
|
+
{ timeout: aSec * 1000, timeoutMsg: `element (${Locator.build(parsedLocator)}) still visible after ${aSec} sec` },
|
|
1827
|
+
)
|
|
1688
1828
|
}
|
|
1689
1829
|
|
|
1690
1830
|
/**
|
|
@@ -1692,74 +1832,72 @@ class Appium extends Webdriver {
|
|
|
1692
1832
|
*
|
|
1693
1833
|
*/
|
|
1694
1834
|
async waitForText(text, sec = null, context = null) {
|
|
1695
|
-
if (this.isWeb) return super.waitForText(text, sec, context)
|
|
1696
|
-
return super.waitForText(text, sec, parseLocator.call(this, context))
|
|
1835
|
+
if (this.isWeb) return super.waitForText(text, sec, context)
|
|
1836
|
+
return super.waitForText(text, sec, parseLocator.call(this, context))
|
|
1697
1837
|
}
|
|
1698
1838
|
}
|
|
1699
1839
|
|
|
1700
1840
|
function parseLocator(locator) {
|
|
1701
|
-
if (!locator) return null
|
|
1841
|
+
if (!locator) return null
|
|
1702
1842
|
|
|
1703
1843
|
if (typeof locator === 'object') {
|
|
1704
1844
|
if (locator.web && this.isWeb) {
|
|
1705
|
-
return parseLocator.call(this, locator.web)
|
|
1845
|
+
return parseLocator.call(this, locator.web)
|
|
1706
1846
|
}
|
|
1707
1847
|
|
|
1708
1848
|
if (locator.android && this.platform === 'android') {
|
|
1709
1849
|
if (typeof locator.android === 'string') {
|
|
1710
|
-
return parseLocator.call(this, locator.android)
|
|
1850
|
+
return parseLocator.call(this, locator.android)
|
|
1711
1851
|
}
|
|
1712
1852
|
// The locator is an Android DataMatcher or ViewMatcher locator so return as is
|
|
1713
|
-
return locator.android
|
|
1853
|
+
return locator.android
|
|
1714
1854
|
}
|
|
1715
1855
|
|
|
1716
1856
|
if (locator.ios && this.platform === 'ios') {
|
|
1717
|
-
return parseLocator.call(this, locator.ios)
|
|
1857
|
+
return parseLocator.call(this, locator.ios)
|
|
1718
1858
|
}
|
|
1719
1859
|
}
|
|
1720
1860
|
|
|
1721
1861
|
if (typeof locator === 'string') {
|
|
1722
|
-
if (locator[0] === '~') return locator
|
|
1723
|
-
if (locator.substr(0, 2) === '//') return locator
|
|
1862
|
+
if (locator[0] === '~') return locator
|
|
1863
|
+
if (locator.substr(0, 2) === '//') return locator
|
|
1724
1864
|
if (locator[0] === '#' && !this.isWeb) {
|
|
1725
1865
|
// hook before webdriverio supports native # locators
|
|
1726
|
-
return parseLocator.call(this, { id: locator.slice(1) })
|
|
1866
|
+
return parseLocator.call(this, { id: locator.slice(1) })
|
|
1727
1867
|
}
|
|
1728
1868
|
|
|
1729
1869
|
if (this.platform === 'android' && !this.isWeb) {
|
|
1730
|
-
const isNativeLocator = /^\-?android=?/.exec(locator)
|
|
1731
|
-
return isNativeLocator
|
|
1732
|
-
? locator
|
|
1733
|
-
: `android=new UiSelector().text("${locator}")`;
|
|
1870
|
+
const isNativeLocator = /^\-?android=?/.exec(locator)
|
|
1871
|
+
return isNativeLocator ? locator : `android=new UiSelector().text("${locator}")`
|
|
1734
1872
|
}
|
|
1735
1873
|
}
|
|
1736
1874
|
|
|
1737
|
-
locator = new Locator(locator, 'xpath')
|
|
1738
|
-
if (locator.type === 'css' && !this.isWeb) throw new Error('Unable to use css locators in apps. Locator strategies for this request: xpath, id, class name or accessibility id')
|
|
1739
|
-
if (locator.type === 'name' && !this.isWeb) throw new Error("Can't locate element by name in Native context. Use either ID, class name or accessibility id")
|
|
1740
|
-
if (locator.type === 'id' && !this.isWeb && this.platform === 'android') return `//*[@resource-id='${locator.value}']
|
|
1741
|
-
return locator.simplify()
|
|
1875
|
+
locator = new Locator(locator, 'xpath')
|
|
1876
|
+
if (locator.type === 'css' && !this.isWeb) throw new Error('Unable to use css locators in apps. Locator strategies for this request: xpath, id, class name or accessibility id')
|
|
1877
|
+
if (locator.type === 'name' && !this.isWeb) throw new Error("Can't locate element by name in Native context. Use either ID, class name or accessibility id")
|
|
1878
|
+
if (locator.type === 'id' && !this.isWeb && this.platform === 'android') return `//*[@resource-id='${locator.value}']`
|
|
1879
|
+
return locator.simplify()
|
|
1742
1880
|
}
|
|
1743
1881
|
|
|
1744
1882
|
// in the end of a file
|
|
1745
1883
|
function onlyForApps(expectedPlatform) {
|
|
1746
|
-
const stack = new Error().stack || ''
|
|
1747
|
-
const re = /Appium.(\w+)/g
|
|
1748
|
-
const caller = stack.split('\n')[2].trim()
|
|
1749
|
-
const m = re.exec(caller)
|
|
1884
|
+
const stack = new Error().stack || ''
|
|
1885
|
+
const re = /Appium.(\w+)/g
|
|
1886
|
+
const caller = stack.split('\n')[2].trim()
|
|
1887
|
+
const m = re.exec(caller)
|
|
1750
1888
|
|
|
1751
1889
|
if (!m) {
|
|
1752
|
-
throw new Error(`Invalid caller ${caller}`)
|
|
1890
|
+
throw new Error(`Invalid caller ${caller}`)
|
|
1753
1891
|
}
|
|
1754
1892
|
|
|
1755
|
-
const callerName = m[1] || m[2]
|
|
1893
|
+
const callerName = m[1] || m[2]
|
|
1756
1894
|
if (!expectedPlatform) {
|
|
1757
1895
|
if (!this.platform) {
|
|
1758
|
-
throw new Error(`${callerName} method can be used only with apps`)
|
|
1896
|
+
throw new Error(`${callerName} method can be used only with apps`)
|
|
1759
1897
|
}
|
|
1760
1898
|
} else if (this.platform !== expectedPlatform.toLowerCase()) {
|
|
1761
|
-
throw new Error(`${callerName} method can be used only with ${expectedPlatform} apps`)
|
|
1899
|
+
throw new Error(`${callerName} method can be used only with ${expectedPlatform} apps`)
|
|
1762
1900
|
}
|
|
1763
1901
|
}
|
|
1764
1902
|
|
|
1765
|
-
export default Appium
|
|
1903
|
+
export default Appium
|