@testim/testim-cli 3.196.0 → 3.200.0
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 +1 -1
- package/cli/onExit.js +12 -1
- package/cli.js +5 -1
- package/commons/constants.js +0 -25
- package/commons/featureFlags.js +2 -0
- package/commons/npmWrapper.js +46 -14
- package/commons/npmWrapper.test.js +182 -6
- package/commons/socket/testResultService.js +4 -14
- package/commons/testimAnalytics.js +0 -1
- package/commons/testimDesiredCapabilitiesBuilder.js +0 -94
- package/commons/testimServicesApi.js +9 -79
- package/executionQueue.js +7 -4
- package/npm-shrinkwrap.json +960 -524
- package/package.json +3 -1
- package/player/stepActions/baseJsStepAction.js +5 -1
- package/player/stepActions/pixelValidationStepAction.js +28 -0
- package/player/stepActions/salesforceAutoLoginStepAction.js +5 -3
- package/player/stepActions/stepActionRegistrar.js +4 -48
- package/player/utils/eyeSdkService.js +230 -0
- package/reports/consoleReporter.js +29 -44
- package/reports/reporter.js +0 -21
- package/runOptions.js +13 -89
- package/runner.js +3 -44
- package/runners/{strategies/LocalStrategy.js → ParallelWorkerManager.js} +59 -68
- package/runners/TestPlanRunner.js +288 -67
- package/runners/runnerUtils.js +73 -0
- package/services/analyticsService.js +94 -0
- package/services/gridService.js +24 -20
- package/services/gridService.test.js +21 -21
- package/stepPlayers/hybridStepPlayback.js +4 -1
- package/stepPlayers/tdkHybridStepPlayback.js +1 -0
- package/testRunHandler.js +23 -5
- package/testRunStatus.js +18 -27
- package/utils.js +5 -5
- package/workers/BaseWorker.js +39 -39
- package/workers/BaseWorker.test.js +1 -1
- package/workers/WorkerExtensionSingleBrowser.js +6 -3
- package/commons/apkUploader/apkUploader.js +0 -46
- package/commons/apkUploader/apkUploaderFactory.js +0 -68
- package/commons/apkUploader/deviceFarmApkUploader.js +0 -41
- package/commons/apkUploader/saucelabsApkUploader.js +0 -36
- package/commons/apkUploader/testObjectApkUploader.js +0 -34
- package/player/mobile/mobileTestPlayer.js +0 -80
- package/player/mobile/mobileWebDriver.js +0 -155
- package/player/mobile/services/frameLocatorMock.js +0 -18
- package/player/mobile/services/mobilePortSelector.js +0 -22
- package/player/mobile/services/mobileTabService.js +0 -241
- package/player/mobile/utils/mobileScreenshotUtils.js +0 -46
- package/player/mobile/utils/mobileWindowUtils.js +0 -84
- package/player/stepActions/mobile/android/androidLocateStepAction.js +0 -122
- package/player/stepActions/mobile/android/androidLongClickStepAction.js +0 -12
- package/player/stepActions/mobile/android/androidScrollStepAction.js +0 -134
- package/player/stepActions/mobile/android/androidSpecialKeyStepAction.js +0 -22
- package/player/stepActions/mobile/android/androidSwipeStepAction.js +0 -32
- package/player/stepActions/mobile/androidGlobalActionStepAction.js +0 -12
- package/player/stepActions/mobile/androidTapStepAction.js +0 -19
- package/player/stepActions/mobile/androidTextChangeStepAction.js +0 -23
- package/player/stepActions/mobile/ios/iosLocateStepAction.js +0 -124
- package/player/stepActions/mobile/ios/iosScrollStepAction.js +0 -76
- package/runners/AnonymousTestPlanRunner.js +0 -106
- package/runners/BaseRunner.js +0 -42
- package/runners/BaseTestPlanRunner.js +0 -194
- package/runners/DeviceFarmRemoteRunner.js +0 -50
- package/runners/SchedulerRemoteRunner.js +0 -47
- package/runners/strategies/BaseStrategy.js +0 -86
- package/runners/strategies/DeviceFarmStrategy.js +0 -195
- package/runners/strategies/LocalDeviceFarmStrategy.js +0 -12
- package/runners/strategies/LocalTestStrategy.js +0 -14
- package/runners/strategies/Strategy.js +0 -17
- package/workers/WorkerAppium.js +0 -70
|
@@ -1,46 +0,0 @@
|
|
|
1
|
-
const Promise = require('bluebird');
|
|
2
|
-
const utils = require('../../utils');
|
|
3
|
-
const logger = require('../logger').getLogger("apk-uploader");
|
|
4
|
-
const {ArgError} = require('../../errors');
|
|
5
|
-
const reporter = require("../../reports/reporter");
|
|
6
|
-
|
|
7
|
-
class ApkUploader {
|
|
8
|
-
constructor() {
|
|
9
|
-
this._appId = null;
|
|
10
|
-
this._isInFlightRequest = null;
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
uploadApk(vendorAppId, apkFullPath, apkTimeout, projectId, gridData) {
|
|
14
|
-
if (this._appId) {
|
|
15
|
-
return Promise.resolve(this.getAppCaps());
|
|
16
|
-
}
|
|
17
|
-
if (this._isInFlightRequest) {
|
|
18
|
-
return this._isInFlightRequest;
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
this._isInFlightRequest = (vendorAppId
|
|
22
|
-
? Promise.resolve(vendorAppId)
|
|
23
|
-
: utils.runWithRetries(() => this.uploadFile(gridData, apkFullPath, apkTimeout, projectId)))
|
|
24
|
-
.then(res => {
|
|
25
|
-
reporter.onUploadApkFinished(res);
|
|
26
|
-
this._appId = res;
|
|
27
|
-
return this.getAppCaps();
|
|
28
|
-
})
|
|
29
|
-
.catch(err => {
|
|
30
|
-
logger.error("failed to upload apk", {errStack: err.stack});
|
|
31
|
-
throw new ArgError(`Failed to upload apk: ${apkFullPath}`);
|
|
32
|
-
})
|
|
33
|
-
.finally(() => this._isInFlightRequest = null);
|
|
34
|
-
return this._isInFlightRequest;
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
uploadFile(key, apkFullPath, apkTimeout) {
|
|
38
|
-
throw new Error("not implemented");
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
getAppCaps() {
|
|
42
|
-
throw new Error("not implemented");
|
|
43
|
-
}
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
module.exports = ApkUploader;
|
|
@@ -1,68 +0,0 @@
|
|
|
1
|
-
const testObjectApkUploader = require('./testObjectApkUploader');
|
|
2
|
-
const saucelabsApkUploader = require('./saucelabsApkUploader');
|
|
3
|
-
const deviceFarmApkUploader = require('./deviceFarmApkUploader');
|
|
4
|
-
|
|
5
|
-
const reporter = require("../../reports/reporter");
|
|
6
|
-
const path = require('path');
|
|
7
|
-
const Promise = require('bluebird');
|
|
8
|
-
const logger = require('../../commons/logger').getLogger("apk-uploader-factory");
|
|
9
|
-
const { ArgError } = require('../../errors');
|
|
10
|
-
|
|
11
|
-
function uploadApk(browserOptions) {
|
|
12
|
-
const { apkLocation, apkTimeout, ipaLocation, ipaTimeout, project, vendorAppId, gridData } = browserOptions;
|
|
13
|
-
|
|
14
|
-
if(gridData.type === "hostAndPort") {
|
|
15
|
-
return Promise.resolve();
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
if(!apkLocation && !ipaLocation && !vendorAppId) {
|
|
19
|
-
logger.info("App location is not defined");
|
|
20
|
-
throw new ArgError("No App provided. Please specify the location of the APK/IPA to use in this run using the --apk-location flag or the --ipa-location flag");
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
let appFullPath, appTimeout;
|
|
24
|
-
|
|
25
|
-
if(apkLocation) {
|
|
26
|
-
appFullPath = path.resolve(apkLocation);
|
|
27
|
-
appTimeout = apkTimeout;
|
|
28
|
-
} else if(ipaLocation) {
|
|
29
|
-
appFullPath = path.resolve(ipaLocation);
|
|
30
|
-
appTimeout = ipaTimeout;
|
|
31
|
-
}
|
|
32
|
-
const projectId = project;
|
|
33
|
-
|
|
34
|
-
reporter.onUploadApk(appFullPath, vendorAppId);
|
|
35
|
-
|
|
36
|
-
if (gridData.type === "testimMobile") {
|
|
37
|
-
return deviceFarmApkUploader.uploadApk(vendorAppId, appFullPath, appTimeout, projectId, gridData);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
if (gridData.type === "testobject") {
|
|
41
|
-
return testObjectApkUploader.uploadApk(vendorAppId, appFullPath, appTimeout, projectId, gridData);
|
|
42
|
-
}
|
|
43
|
-
|
|
44
|
-
if (gridData.type === "saucelabs") {
|
|
45
|
-
return saucelabsApkUploader.uploadApk(vendorAppId, appFullPath, appTimeout, projectId, gridData);
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
throw new ArgError(`Failed to find matched provider: ${gridData.type}`);
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
function getAppCaps(gridInfo) {
|
|
52
|
-
if (gridInfo.type === "testobject") {
|
|
53
|
-
return testObjectApkUploader.getAppCaps();
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
if (gridInfo.type === "saucelabs") {
|
|
57
|
-
return saucelabsApkUploader.getAppCaps();
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
if (gridInfo.type === "testimMobile") {
|
|
61
|
-
return deviceFarmApkUploader.getAppCaps();
|
|
62
|
-
}
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
module.exports = {
|
|
66
|
-
uploadApk,
|
|
67
|
-
getAppCaps
|
|
68
|
-
};
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
const path = require('path');
|
|
2
|
-
const crypto = require('crypto');
|
|
3
|
-
const ApkUploader = require('./apkUploader');
|
|
4
|
-
const httpRequest = require('../httpRequest');
|
|
5
|
-
const Promise = require('bluebird');
|
|
6
|
-
const fs = Promise.promisifyAll(require('fs'));
|
|
7
|
-
const testimServicesApi = require('../testimServicesApi');
|
|
8
|
-
|
|
9
|
-
class DeviceFarmApkUploader extends ApkUploader {
|
|
10
|
-
constructor() {
|
|
11
|
-
super();
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
uploadFile({arn}, apkFullPath, apkTimeout, projectId) {
|
|
15
|
-
let apkPathObj = {};
|
|
16
|
-
try {
|
|
17
|
-
apkPathObj = path.parse(apkFullPath);
|
|
18
|
-
} catch (error) {
|
|
19
|
-
return Promise.reject(new TypeError('Apk path is not valid.'));
|
|
20
|
-
}
|
|
21
|
-
return fs.readFileAsync(apkFullPath)
|
|
22
|
-
.then(apkBuffer => {
|
|
23
|
-
const apkHash = crypto.createHash('md5').update(apkBuffer).digest("hex");
|
|
24
|
-
const apkName = `${apkHash}${apkPathObj.ext}`;
|
|
25
|
-
return Promise.all([testimServicesApi.getAppUploadUrl(projectId, arn, apkName), apkBuffer]);
|
|
26
|
-
})
|
|
27
|
-
.spread((app, apkBuffer) => {
|
|
28
|
-
if(app.status === 'SUCCEEDED') {
|
|
29
|
-
return app.arn;
|
|
30
|
-
}
|
|
31
|
-
return httpRequest.put(app.url, apkBuffer, {"Content-Type": "application/octet-stream"}, apkTimeout)
|
|
32
|
-
.then(() => app.arn);
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
getAppCaps() {
|
|
37
|
-
return {appArn: this._appId};
|
|
38
|
-
}
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
module.exports = new DeviceFarmApkUploader();
|
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
const utils = require('../../utils');
|
|
2
|
-
const ApkUploader = require('./apkUploader');
|
|
3
|
-
const httpRequest = require('../httpRequest');
|
|
4
|
-
const Promise = require('bluebird');
|
|
5
|
-
const fs = Promise.promisifyAll(require('fs'));
|
|
6
|
-
const path = require('path');
|
|
7
|
-
|
|
8
|
-
const SAUCE_LABS_API_URL = 'https://saucelabs.com/rest';
|
|
9
|
-
|
|
10
|
-
class SaucelabsApkUploader extends ApkUploader {
|
|
11
|
-
constructor() {
|
|
12
|
-
super();
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
uploadFile({ user, key }, apkFullPath, apkTimeout) {
|
|
16
|
-
const authHeader = utils.buildBasicHeader(user, key);
|
|
17
|
-
const fileName = `${Date.now()}_${path.basename(apkFullPath)}`;
|
|
18
|
-
return fs.readFileAsync(apkFullPath)
|
|
19
|
-
.then(apkBuffer => httpRequest.post({
|
|
20
|
-
url: `${SAUCE_LABS_API_URL}/v1/storage/${user}/${fileName}?overwrite=true`,
|
|
21
|
-
body: apkBuffer,
|
|
22
|
-
headers: {
|
|
23
|
-
Authorization: authHeader,
|
|
24
|
-
'Content-Type': 'application/octet-stream',
|
|
25
|
-
},
|
|
26
|
-
timeout: apkTimeout,
|
|
27
|
-
}))
|
|
28
|
-
.then(res => res.filename);
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
getAppCaps() {
|
|
32
|
-
return { app: `sauce-storage:${this._appId}` };
|
|
33
|
-
}
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
module.exports = new SaucelabsApkUploader();
|
|
@@ -1,34 +0,0 @@
|
|
|
1
|
-
const utils = require('../../utils');
|
|
2
|
-
const ApkUploader = require('./apkUploader');
|
|
3
|
-
const httpRequest = require('../httpRequest');
|
|
4
|
-
const Promise = require('bluebird');
|
|
5
|
-
const fs = Promise.promisifyAll(require('fs'));
|
|
6
|
-
|
|
7
|
-
const TEST_OBJECT_API_URL = 'https://app.testobject.com/api';
|
|
8
|
-
|
|
9
|
-
class TestObjectApkUploader extends ApkUploader {
|
|
10
|
-
constructor() {
|
|
11
|
-
super();
|
|
12
|
-
}
|
|
13
|
-
|
|
14
|
-
uploadFile({ key }, apkFullPath, apkTimeout) {
|
|
15
|
-
const authHeader = utils.buildBasicHeader('', key);
|
|
16
|
-
return fs.readFileAsync(apkFullPath)
|
|
17
|
-
.then(apkBuffer => httpRequest.post({
|
|
18
|
-
url: `${TEST_OBJECT_API_URL}/storage/upload`,
|
|
19
|
-
body: apkBuffer,
|
|
20
|
-
headers: {
|
|
21
|
-
Authorization: authHeader,
|
|
22
|
-
'Content-Type': 'application/octet-stream',
|
|
23
|
-
'App-Identifier': String(Date.now()),
|
|
24
|
-
},
|
|
25
|
-
timeout: apkTimeout,
|
|
26
|
-
}));
|
|
27
|
-
}
|
|
28
|
-
|
|
29
|
-
getAppCaps() {
|
|
30
|
-
return { testobject_app_id: this._appId };
|
|
31
|
-
}
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
module.exports = new TestObjectApkUploader();
|
|
@@ -1,80 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const MobileTabService = require('./services/mobileTabService');
|
|
4
|
-
const MobilePortSelector = require('./services/mobilePortSelector');
|
|
5
|
-
|
|
6
|
-
const windowCreationListener = require('../services/windowCreationListener');
|
|
7
|
-
const CookieUtils = () => {};
|
|
8
|
-
const StepActionUtils = require('../utils/stepActionUtils');
|
|
9
|
-
const downloadsApiUtils = require('../utils/downloadsApiUtils');
|
|
10
|
-
const FrameLocatorMock = require('./services/frameLocatorMock');
|
|
11
|
-
|
|
12
|
-
const sessionPlayer = require('../../commons/getSessionPlayerRequire');
|
|
13
|
-
|
|
14
|
-
const player = sessionPlayer.sessionPlayer;
|
|
15
|
-
// delete after https://github.com/testimio/clickim/pull/3430 release to the store
|
|
16
|
-
const assetService = sessionPlayer.assetService;
|
|
17
|
-
const StepActionFactory = sessionPlayer.stepActionFactory;
|
|
18
|
-
const PlaybackTimeoutCalculator = require('../services/playbackTimeoutCalculator');
|
|
19
|
-
|
|
20
|
-
const MobileWebDriver = require('./mobileWebDriver');
|
|
21
|
-
// delete after https://github.com/testimio/clickim/pull/3430 release to the store
|
|
22
|
-
const CryptoJS = require('crypto-js');
|
|
23
|
-
|
|
24
|
-
class MobileTestPlayer {
|
|
25
|
-
constructor(id, userParamsData, projectType) {
|
|
26
|
-
this.driver = new MobileWebDriver();
|
|
27
|
-
this.id = id;
|
|
28
|
-
const stepActionUtils = new StepActionUtils(this.driver);
|
|
29
|
-
this.stepActionFactory = new StepActionFactory(stepActionUtils);
|
|
30
|
-
require('../stepActions/stepActionRegistrar')(this.driver, this.stepActionFactory, projectType);
|
|
31
|
-
|
|
32
|
-
if (assetService.setMd5) {
|
|
33
|
-
// delete after https://github.com/testimio/clickim/pull/3430 release to the store
|
|
34
|
-
assetService.setMd5(CryptoJS);
|
|
35
|
-
}
|
|
36
|
-
this.mobileTabService = MobileTabService(this.driver);
|
|
37
|
-
this.windowCreationListener = windowCreationListener;
|
|
38
|
-
this.playbackTimeoutCalculator = new PlaybackTimeoutCalculator();
|
|
39
|
-
|
|
40
|
-
this.mobileTabService.createSession(id);
|
|
41
|
-
|
|
42
|
-
this.sessionPlayer = new player(id, this.mobileTabService, CookieUtils(this.driver),
|
|
43
|
-
windowCreationListener, FrameLocatorMock, MobilePortSelector,
|
|
44
|
-
null, downloadsApiUtils, stepActionUtils,
|
|
45
|
-
this.stepActionFactory, this.playbackTimeoutCalculator);
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
this.sessionPlayer.playbackManager.isRemoteSession = true;
|
|
49
|
-
this.sessionPlayer.playbackManager.isLocalRun = false;
|
|
50
|
-
|
|
51
|
-
this.sessionPlayer.playbackManager.userParamsData = userParamsData || {};
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
getSessionId() {
|
|
55
|
-
return this.driver.getSessionId();
|
|
56
|
-
}
|
|
57
|
-
|
|
58
|
-
onDone() {
|
|
59
|
-
return this.driver.end()
|
|
60
|
-
.finally(() => {
|
|
61
|
-
this.sessionPlayer = null;
|
|
62
|
-
this.mobileTabService = null;
|
|
63
|
-
this.stepActionFactory = null;
|
|
64
|
-
this.driver = null;
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
clearSessionTabs() {
|
|
69
|
-
this.mobileTabService.clearAllTabs(this.id);
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
addTab(openerStepId) {
|
|
73
|
-
return this.mobileTabService.addNewTab(this.id, 0, openerStepId)
|
|
74
|
-
.then(() => {
|
|
75
|
-
return this.sessionPlayer.addPlaybackFrameHandler(0);
|
|
76
|
-
});
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
module.exports = MobileTestPlayer;
|
|
@@ -1,155 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const Promise = require('bluebird');
|
|
4
|
-
const desiredCapabilitiesBuilder = require('../../commons/testimDesiredCapabilitiesBuilder');
|
|
5
|
-
const SeleniumError = require('../../errors').SeleniumError;
|
|
6
|
-
const ArgError = require('../../errors').ArgError;
|
|
7
|
-
const Webdriver = require('../webdriver');
|
|
8
|
-
const { extractElementId } = require('../../utils');
|
|
9
|
-
const logger = require('../../commons/logger').getLogger("mobile-web-driver");
|
|
10
|
-
|
|
11
|
-
class MobileWebDriver extends Webdriver {
|
|
12
|
-
|
|
13
|
-
init(browserOptions, gridInfo, nativeAppData, testName, testResultId) {
|
|
14
|
-
const capabilities = desiredCapabilitiesBuilder.buildAppiumOptions(browserOptions, gridInfo, nativeAppData, testName);
|
|
15
|
-
const packageName = nativeAppData.packageName;
|
|
16
|
-
|
|
17
|
-
return this.initClient(capabilities, testName, testResultId)
|
|
18
|
-
.then(() => this.switchToNativeContext())
|
|
19
|
-
.then(() => this.isAppInstalled(packageName))
|
|
20
|
-
.then(isInstalled => {
|
|
21
|
-
if (!isInstalled) {
|
|
22
|
-
return Promise.reject(new ArgError("Application not installed! " + packageName));
|
|
23
|
-
}
|
|
24
|
-
return this.launch();
|
|
25
|
-
})
|
|
26
|
-
.catch(err => {
|
|
27
|
-
if (err.seleniumStack) {
|
|
28
|
-
return Promise.reject(new SeleniumError(err.seleniumStack));
|
|
29
|
-
}
|
|
30
|
-
if (err instanceof ArgError) {
|
|
31
|
-
return Promise.reject(err);
|
|
32
|
-
}
|
|
33
|
-
return Promise.reject(new Error("failed to init client driver"));
|
|
34
|
-
});
|
|
35
|
-
}
|
|
36
|
-
|
|
37
|
-
//Override methods
|
|
38
|
-
|
|
39
|
-
getElementLocation(target) {
|
|
40
|
-
return this.elementIdLocation(extractElementId(target.seleniumElement));
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
setText(el, text) {
|
|
44
|
-
return this.setImmediateValue(extractElementId(el), text);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
async getTargetText(target) {
|
|
48
|
-
return target.attributes.text || target.attributes['content-desc'] || "";
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
//End override methods
|
|
52
|
-
|
|
53
|
-
switchToNativeContext() {
|
|
54
|
-
return this.context("NATIVE_APP");
|
|
55
|
-
}
|
|
56
|
-
|
|
57
|
-
longClick(selector) {
|
|
58
|
-
const attr = [{
|
|
59
|
-
action: 'longPress',
|
|
60
|
-
selector
|
|
61
|
-
}];
|
|
62
|
-
|
|
63
|
-
return this.touchAction(attr);
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
tap(selector) {
|
|
67
|
-
let attr = [{
|
|
68
|
-
action: 'tap',
|
|
69
|
-
selector: selector
|
|
70
|
-
}];
|
|
71
|
-
|
|
72
|
-
return this.touchAction(attr);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
touch(x, y) {
|
|
76
|
-
let attr = {
|
|
77
|
-
action: 'tap',
|
|
78
|
-
x: x,
|
|
79
|
-
y: y
|
|
80
|
-
};
|
|
81
|
-
return this.touchAction(attr);
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
scroll(start, end, duration = 1000) {
|
|
85
|
-
// https://github.com/appium/appium-android-driver/blob/master/lib/commands/touch.js (doTouchDrag)
|
|
86
|
-
const down = {action: 'longPress', options: {x: parseInt(start.x), y: parseInt(start.y), duration}};
|
|
87
|
-
const move = {action: 'moveTo', options: {x: parseInt(end.x), y: parseInt(end.y)}};
|
|
88
|
-
const up = {action: 'release'};
|
|
89
|
-
return this.touchPerform([down, move, up]);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
swipe(start, end, duration = 250) {
|
|
93
|
-
// https://github.com/appium/appium-android-driver/blob/master/lib/commands/touch.js
|
|
94
|
-
const down = {action: 'press', options: {x: parseInt(start.x), y: parseInt(start.y)}};
|
|
95
|
-
const wait = {action: 'wait', options: {ms: duration}};
|
|
96
|
-
const move = {action: 'moveTo', options: {x: parseInt(end.x), y: parseInt(end.y)}};
|
|
97
|
-
const up = {action: 'release'};
|
|
98
|
-
return this.touchPerform([down, wait, move, up]);
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
executeImeAction(action) {
|
|
102
|
-
// Required Appium version: 1.9.2.
|
|
103
|
-
// http://appium.io/docs/en/writing-running-appium/android/android-ime/
|
|
104
|
-
return this.executeJS('mobile: performEditorAction', {action});
|
|
105
|
-
}
|
|
106
|
-
|
|
107
|
-
getDeviceInfo() {
|
|
108
|
-
// http://appium.io/docs/en/commands/mobile-command/
|
|
109
|
-
return this.executeJS('mobile:deviceInfo')
|
|
110
|
-
.catch(err => {
|
|
111
|
-
logger.warn(`getDeviceInfo failed`, { err });
|
|
112
|
-
return {};
|
|
113
|
-
})
|
|
114
|
-
.then(deviceInfo => {
|
|
115
|
-
if (deviceInfo.value && deviceInfo.value.model && deviceInfo.value.platformVersion && deviceInfo.value.apiVersion) {
|
|
116
|
-
return {
|
|
117
|
-
'device': deviceInfo.value.model,
|
|
118
|
-
'os': deviceInfo.value.platformVersion + ` (API ${deviceInfo.value.apiVersion})`
|
|
119
|
-
};
|
|
120
|
-
}
|
|
121
|
-
return {};
|
|
122
|
-
})
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
getPackageInfo(packageName) {
|
|
126
|
-
// http://appium.io/docs/en/commands/mobile-command/
|
|
127
|
-
// Android only. Executes ADB shell commands (appium's "Relaxed Security" must be enabled)
|
|
128
|
-
return this.executeJS('mobile:shell', { 'command': `dumpsys package ${packageName} | grep -E \"versionName|versionCode\"` })
|
|
129
|
-
.catch(err => {
|
|
130
|
-
logger.warn(`getPackageInfo failed at appium command mobile:shell`, { packageName, err });
|
|
131
|
-
return {};
|
|
132
|
-
})
|
|
133
|
-
.then(shellResult => {
|
|
134
|
-
try {
|
|
135
|
-
// Shell result from ADB looks like `versionCode=620 minSdk=24 targetSdk=28\n versionName=0.6.2`
|
|
136
|
-
const packageInfo = shellResult.value.split(/\s/).filter(Boolean).reduce((obj, item) => {
|
|
137
|
-
const [key, value] = item.split('=')
|
|
138
|
-
return { ...obj, [key]: value };
|
|
139
|
-
}, {});
|
|
140
|
-
|
|
141
|
-
if (packageInfo && packageInfo.versionName && packageInfo.versionCode){
|
|
142
|
-
return {
|
|
143
|
-
'autVersion': packageInfo.versionName + ` (${packageInfo.versionCode})`
|
|
144
|
-
};
|
|
145
|
-
}
|
|
146
|
-
return {};
|
|
147
|
-
} catch (err) {
|
|
148
|
-
logger.warn(`getPackageInfo failed parsing shell result`, { packageName, err });
|
|
149
|
-
return {};
|
|
150
|
-
}
|
|
151
|
-
})
|
|
152
|
-
}
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
module.exports = MobileWebDriver;
|
|
@@ -1,18 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
const Promise = require('bluebird');
|
|
3
|
-
|
|
4
|
-
class FrameLocatorMock {
|
|
5
|
-
|
|
6
|
-
constructor() {}
|
|
7
|
-
|
|
8
|
-
findFrame() {
|
|
9
|
-
return Promise.resolve({
|
|
10
|
-
frameOffset: {top: 0, left: 0},
|
|
11
|
-
tabId: 0,
|
|
12
|
-
frameId: 0,
|
|
13
|
-
testimFullFrameId: 0
|
|
14
|
-
});
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
module.exports = FrameLocatorMock;
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
const Promise = require('bluebird');
|
|
3
|
-
|
|
4
|
-
// Legacy code not supported in selenium mode
|
|
5
|
-
class MobilePortSelector {
|
|
6
|
-
constructor() {
|
|
7
|
-
}
|
|
8
|
-
|
|
9
|
-
select() {
|
|
10
|
-
return Promise.resolve({
|
|
11
|
-
testimFullFrameId : 0
|
|
12
|
-
});
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
prepare() {
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
handleLegacyDataCaching() {
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
module.exports = new MobilePortSelector();
|