@testim/testim-cli 3.193.0 → 3.197.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/codim/codim-npm-package/index.ts +1 -0
- package/commons/constants.js +0 -25
- package/commons/featureFlags.js +2 -0
- package/commons/socket/testResultService.js +4 -14
- package/commons/testimAnalytics.js +0 -1
- package/commons/testimDesiredCapabilitiesBuilder.js +0 -95
- package/commons/testimServicesApi.js +10 -80
- package/executionQueue.js +7 -4
- package/npm-shrinkwrap.json +956 -520
- package/package.json +3 -1
- package/player/chromeLauncherTestPlayer.js +5 -2
- package/player/stepActions/apiStepAction.js +1 -0
- package/player/stepActions/baseJsStepAction.js +5 -1
- package/player/stepActions/pixelValidationStepAction.js +28 -0
- package/player/stepActions/salesforceAutoLoginStepAction.js +39 -0
- package/player/stepActions/scripts/focusElement.js +5 -3
- package/player/stepActions/stepActionRegistrar.js +5 -47
- package/player/utils/eyeSdkService.js +230 -0
- package/reports/consoleReporter.js +0 -20
- package/reports/reporter.js +0 -21
- package/runOptions.js +13 -89
- package/runner.js +9 -46
- package/runners/{strategies/LocalStrategy.js → ParallelWorkerManager.js} +60 -66
- package/runners/TestPlanRunner.js +286 -67
- package/runners/runnerUtils.js +73 -0
- package/{runners/strategies/BaseStrategy.js → services/analyticsService.js} +41 -28
- package/services/gridService.js +24 -16
- package/services/gridService.test.js +21 -21
- package/services/lambdatestService.js +1 -1
- package/testRunHandler.js +1 -1
- package/testRunStatus.js +30 -20
- package/utils.js +5 -5
- package/workers/BaseWorker.js +38 -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/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,84 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const Promise = require('bluebird');
|
|
4
|
-
const logger = require('../../../commons/logger').getLogger("mobile-window-utils");
|
|
5
|
-
|
|
6
|
-
function WindowUtils(id, driver){
|
|
7
|
-
this.id = id;
|
|
8
|
-
this.driver = driver;
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
WindowUtils.prototype.getLocation = function(){
|
|
12
|
-
return this.driver.getUrl();
|
|
13
|
-
};
|
|
14
|
-
|
|
15
|
-
WindowUtils.prototype.stopListeningToScroll = function(){
|
|
16
|
-
return Promise.resolve();
|
|
17
|
-
};
|
|
18
|
-
|
|
19
|
-
WindowUtils.prototype.resumeListeningToScroll = function(){
|
|
20
|
-
return Promise.resolve();
|
|
21
|
-
};
|
|
22
|
-
|
|
23
|
-
WindowUtils.prototype.scrollToPosition = function(){
|
|
24
|
-
return Promise.resolve();
|
|
25
|
-
};
|
|
26
|
-
|
|
27
|
-
WindowUtils.prototype.getCurrentScrollPosition = function(){
|
|
28
|
-
return Promise.resolve();
|
|
29
|
-
};
|
|
30
|
-
|
|
31
|
-
WindowUtils.prototype.navigate = function(){
|
|
32
|
-
return Promise.resolve();
|
|
33
|
-
};
|
|
34
|
-
|
|
35
|
-
WindowUtils.prototype.getViewportSize = function(){
|
|
36
|
-
return this.driver.getViewportSize();
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
WindowUtils.prototype.getFullPageSize = function(){
|
|
40
|
-
return Promise.resolve({ height : 1920, width: 1080 });
|
|
41
|
-
};
|
|
42
|
-
|
|
43
|
-
WindowUtils.prototype.extractToNewWindow = function(){
|
|
44
|
-
return Promise.resolve();
|
|
45
|
-
};
|
|
46
|
-
|
|
47
|
-
WindowUtils.prototype.setViewportSize = function() {
|
|
48
|
-
return Promise.resolve();
|
|
49
|
-
};
|
|
50
|
-
|
|
51
|
-
WindowUtils.prototype.validatePageIsAvailable = function(){
|
|
52
|
-
return Promise.resolve();
|
|
53
|
-
};
|
|
54
|
-
|
|
55
|
-
WindowUtils.prototype.focusTab = function(){
|
|
56
|
-
return Promise.resolve();
|
|
57
|
-
};
|
|
58
|
-
|
|
59
|
-
WindowUtils.prototype.quit = function(){
|
|
60
|
-
return undefined;
|
|
61
|
-
};
|
|
62
|
-
|
|
63
|
-
WindowUtils.prototype.getOsAndBrowser = function() {
|
|
64
|
-
var packageInfoPromise;
|
|
65
|
-
// TODO: Add support for AUT version for iOS (https://testim.atlassian.net/browse/TES-4211)
|
|
66
|
-
if (this.driver.client && this.driver.client.desiredCapabilities && this.driver.client.desiredCapabilities.appPackage &&
|
|
67
|
-
this.driver.isAndroid()){
|
|
68
|
-
packageInfoPromise = this.driver.getPackageInfo(this.driver.client.desiredCapabilities.appPackage);
|
|
69
|
-
} else {
|
|
70
|
-
logger.warn(`getOsAndBrowser failed to extract AUT package from desiredCapabilities`);
|
|
71
|
-
packageInfoPromise = Promise.resolve({});
|
|
72
|
-
}
|
|
73
|
-
|
|
74
|
-
return Promise.all([this.driver.getDeviceInfo(), packageInfoPromise])
|
|
75
|
-
.catch(err => {
|
|
76
|
-
logger.warn(`getOsAndBrowser failed`, { err });
|
|
77
|
-
return {}
|
|
78
|
-
})
|
|
79
|
-
.spread((deviceInfo, packageInfo) => {
|
|
80
|
-
return {...packageInfo, ...deviceInfo};
|
|
81
|
-
});
|
|
82
|
-
};
|
|
83
|
-
|
|
84
|
-
module.exports = WindowUtils;
|
|
@@ -1,122 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const StepAction = require('../../stepAction');
|
|
4
|
-
const sessionPlayer = require('../../../../commons/getSessionPlayerRequire');
|
|
5
|
-
const mobileUtils = sessionPlayer.mobileUtils;
|
|
6
|
-
const { getElementAttributesMap, getXPathSelector } = require('appium-dom-utils');
|
|
7
|
-
const logger = require('../../../../commons/logger').getLogger("android-locate-step-action");
|
|
8
|
-
|
|
9
|
-
const { JSDOM, VirtualConsole } = require('jsdom');
|
|
10
|
-
|
|
11
|
-
function createUtils(driver) {
|
|
12
|
-
return class {
|
|
13
|
-
static getFrameIdByTestimFrameId() {}
|
|
14
|
-
|
|
15
|
-
static setElementResultDataOnContext(target, result) {
|
|
16
|
-
const { dom, element, success } = result;
|
|
17
|
-
if (!success) {
|
|
18
|
-
return Promise.resolve();
|
|
19
|
-
}
|
|
20
|
-
const selector = getXPathSelector(element);
|
|
21
|
-
if (!selector) {
|
|
22
|
-
return Promise.reject(new Error('Could not build Android selector'));
|
|
23
|
-
}
|
|
24
|
-
target.appiumSelector = selector;
|
|
25
|
-
|
|
26
|
-
const attributes = getElementAttributesMap(element);
|
|
27
|
-
delete attributes["testim_dom_element_id"];
|
|
28
|
-
target.attributes = attributes;
|
|
29
|
-
|
|
30
|
-
return driver.getElementBySelector(target.appiumSelector)
|
|
31
|
-
.then(seleniumResponse => target.seleniumElement = seleniumResponse.value);
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
static getElementRectangle(target) {
|
|
35
|
-
if (mobileUtils) {
|
|
36
|
-
const {attributes} = target;
|
|
37
|
-
const {left, top, right, bottom} = mobileUtils.parseAndroidRectFromString(attributes.bounds);
|
|
38
|
-
return Promise.resolve({left, top, width: right - left, height: bottom - top});
|
|
39
|
-
}
|
|
40
|
-
return driver.getElementRect(target);
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
static getOffsets() {
|
|
44
|
-
return Promise.resolve([]);
|
|
45
|
-
}
|
|
46
|
-
|
|
47
|
-
static htmlStringToDom(htmlString, url) {
|
|
48
|
-
|
|
49
|
-
const virtualConsole = new VirtualConsole();
|
|
50
|
-
const jsdom = new JSDOM(htmlString, {
|
|
51
|
-
virtualConsole,
|
|
52
|
-
features: {
|
|
53
|
-
FetchExternalResources: ["script", "frame", "iframe", "link", "img"]
|
|
54
|
-
},
|
|
55
|
-
contentType: "text/xml"
|
|
56
|
-
}) || {};
|
|
57
|
-
|
|
58
|
-
const {document} = jsdom.window;
|
|
59
|
-
process.nextTick(() => {
|
|
60
|
-
jsdom.window.close();
|
|
61
|
-
});
|
|
62
|
-
document.TESTIM_URL = url;
|
|
63
|
-
var elements = Array.from(document.querySelectorAll("*"));
|
|
64
|
-
elements.forEach(function (element, index) {
|
|
65
|
-
element.setAttribute("testim_dom_element_id", index);
|
|
66
|
-
});
|
|
67
|
-
return document;
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
static isVisible(target) {
|
|
71
|
-
if (target.seleniumElement) {
|
|
72
|
-
return Promise.resolve(true);
|
|
73
|
-
}
|
|
74
|
-
return Promise.resolve(false);
|
|
75
|
-
}
|
|
76
|
-
};
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
class AndroidLocateStepAction extends StepAction {
|
|
81
|
-
execute() {
|
|
82
|
-
return this.driver.getSource()
|
|
83
|
-
.then(res => Promise.resolve({html: res.value}));
|
|
84
|
-
}
|
|
85
|
-
|
|
86
|
-
static getUtils(driver) {
|
|
87
|
-
return createUtils(driver);
|
|
88
|
-
}
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
static getFrameIdByTestimFrameId(...args) {
|
|
92
|
-
logger.warn('Unplanned access to getFrameIdByTestimFrameId() #Android');
|
|
93
|
-
throw new Error('Use .getUtils() instead');
|
|
94
|
-
}
|
|
95
|
-
|
|
96
|
-
static setElementResultDataOnContext(...args) {
|
|
97
|
-
logger.warn('Unplanned access to setElementResultDataOnContext() #Android');
|
|
98
|
-
throw new Error('Use .getUtils() instead');
|
|
99
|
-
}
|
|
100
|
-
|
|
101
|
-
static getElementRectangle(...args) {
|
|
102
|
-
logger.warn('Unplanned access to getElementRectangle() #Android');
|
|
103
|
-
throw new Error('Use .getUtils() instead');
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
static getOffsets(...args) {
|
|
107
|
-
logger.warn('Unplanned access to getOffsets() #Android');
|
|
108
|
-
throw new Error('Use .getUtils() instead');
|
|
109
|
-
}
|
|
110
|
-
|
|
111
|
-
static htmlStringToDom(...args) {
|
|
112
|
-
logger.warn('Unplanned access to htmlStringToDom() #Android');
|
|
113
|
-
throw new Error('Use .getUtils() instead');
|
|
114
|
-
}
|
|
115
|
-
|
|
116
|
-
static isVisible(...args) {
|
|
117
|
-
logger.warn('Unplanned access to isVisible() #Android');
|
|
118
|
-
throw new Error('Use .getUtils() instead');
|
|
119
|
-
}
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
module.exports = AndroidLocateStepAction;
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const StepAction = require('../../stepAction');
|
|
4
|
-
|
|
5
|
-
class AndroidLongClickStepAction extends StepAction {
|
|
6
|
-
performAction() {
|
|
7
|
-
return this.driver.longClick(this.getTarget().appiumSelector);
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
module.exports = AndroidLongClickStepAction;
|
|
12
|
-
|
|
@@ -1,134 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
const Promise = require('bluebird');
|
|
3
|
-
const Directions = { Up: "scroll_up", Down: "scroll_down", Left: "scroll_left", Right: "scroll_right", };
|
|
4
|
-
const _ = require('lodash');
|
|
5
|
-
const SwipeStepAction = require('./androidSwipeStepAction');
|
|
6
|
-
const logger = require('../../../../commons/logger').getLogger('android-scroll-step-action');
|
|
7
|
-
const sessionPlayer = require('../../../../commons/getSessionPlayerRequire');
|
|
8
|
-
const constants = sessionPlayer.commonConstants.stepResult;
|
|
9
|
-
class AndroidScrollStepAction extends SwipeStepAction {
|
|
10
|
-
|
|
11
|
-
static getDirection(event) {
|
|
12
|
-
const { distance } = event;
|
|
13
|
-
if (Math.abs(distance.x) < Math.abs(distance.y)) {
|
|
14
|
-
// vertical
|
|
15
|
-
return distance.y > 0 ? Directions.Down : Directions.Up;
|
|
16
|
-
} else {
|
|
17
|
-
// horizontal
|
|
18
|
-
return distance.x > 0 ? Directions.Right : Directions.Left;
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
static getScrollCoordinatesFromPageScroll(target, direction, offsetFromStart = 0.75) {
|
|
23
|
-
const {rect} = target;
|
|
24
|
-
const smallOffset = 5;
|
|
25
|
-
let startX, startY, endX, endY;
|
|
26
|
-
switch (direction) {
|
|
27
|
-
case Directions.Down:
|
|
28
|
-
startX = rect.left + (rect.width / 2);
|
|
29
|
-
startY = rect.top + (rect.height * offsetFromStart);
|
|
30
|
-
endX = startX;
|
|
31
|
-
endY = rect.top + smallOffset;
|
|
32
|
-
break;
|
|
33
|
-
case Directions.Up:
|
|
34
|
-
startX = rect.left + (rect.width / 2);
|
|
35
|
-
startY = rect.top + (rect.height * (1 - offsetFromStart));
|
|
36
|
-
endX = startX;
|
|
37
|
-
endY = rect.top + rect.height - smallOffset;
|
|
38
|
-
break;
|
|
39
|
-
case Directions.Right:
|
|
40
|
-
startX = rect.left + (rect.width * offsetFromStart);
|
|
41
|
-
startY = rect.top + (rect.height / 2);
|
|
42
|
-
endX = rect.left + smallOffset;
|
|
43
|
-
endY = startY;
|
|
44
|
-
break;
|
|
45
|
-
case Directions.Left:
|
|
46
|
-
startX = rect.left + (rect.width * (1 - offsetFromStart));
|
|
47
|
-
startY = rect.top + (rect.height / 2);
|
|
48
|
-
endX = rect.left + rect.width - smallOffset;
|
|
49
|
-
endY = startY;
|
|
50
|
-
break;
|
|
51
|
-
}
|
|
52
|
-
return {start: {x: startX, y: startY}, end: {x: endX, y: endY}};
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
scrollToElement(step, scrolledOnElementTarget, scrollDirection) {
|
|
56
|
-
const runTimeout = this.context.data.timeToPlayStep;
|
|
57
|
-
const runMaxTime = Date.now() + runTimeout;
|
|
58
|
-
return this.locateElementPlayer.findElements([this.step.scrollToElement], step, this.frameHandler)
|
|
59
|
-
.catch((err) => {
|
|
60
|
-
const { start, end } = AndroidScrollStepAction.getScrollCoordinatesFromPageScroll(scrolledOnElementTarget, scrollDirection, 0.75);
|
|
61
|
-
if (Date.now() > runMaxTime) {
|
|
62
|
-
logger.info("Scroll to element reached timeout");
|
|
63
|
-
throw Object.assign(new Error("Scroll timeout reached:" + err.message), {
|
|
64
|
-
id: this.step.id,
|
|
65
|
-
success: false,
|
|
66
|
-
shouldRetry: true,
|
|
67
|
-
isTimeout: true,
|
|
68
|
-
errorType: constants.ACTION_TIMEOUT
|
|
69
|
-
});
|
|
70
|
-
}
|
|
71
|
-
return this.driver.scroll(start, end)
|
|
72
|
-
.then(() => this.scrollToElement(step, scrolledOnElementTarget, scrollDirection));
|
|
73
|
-
});
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
getScrollToElementDirection(events) {
|
|
77
|
-
const eventDirections = events.reduce((directions, event) => {
|
|
78
|
-
directions[AndroidScrollStepAction.getDirection(event)]++;
|
|
79
|
-
return directions;
|
|
80
|
-
}, {
|
|
81
|
-
[Directions.Up]: 0,
|
|
82
|
-
[Directions.Down]: 0,
|
|
83
|
-
[Directions.Left]: 0,
|
|
84
|
-
[Directions.Right]: 0
|
|
85
|
-
});
|
|
86
|
-
const maxDirectionsEvents = _.max(_.values(eventDirections));
|
|
87
|
-
|
|
88
|
-
return _.findKey(eventDirections, e => e === maxDirectionsEvents);
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
static getScrollCoordinatesFromSwipe({elementPositionTouchDown, elementPositionTouchUp}, {rect}) {
|
|
92
|
-
return {
|
|
93
|
-
start: {
|
|
94
|
-
x: rect.left + rect.width * elementPositionTouchDown.percentX,
|
|
95
|
-
y: rect.top + rect.height * elementPositionTouchDown.percentY,
|
|
96
|
-
},
|
|
97
|
-
end: {
|
|
98
|
-
x: rect.left + rect.width * elementPositionTouchUp.percentX,
|
|
99
|
-
y: rect.top + rect.height * elementPositionTouchUp.percentY,
|
|
100
|
-
},
|
|
101
|
-
};
|
|
102
|
-
}
|
|
103
|
-
|
|
104
|
-
performAction(_, step) {
|
|
105
|
-
if (!step) {
|
|
106
|
-
step = this.step;
|
|
107
|
-
logger.warn('a falsy step object was received in performAction(). Using stepData instead', {stepType: this.step.type});
|
|
108
|
-
}
|
|
109
|
-
const target = this.getTarget();
|
|
110
|
-
if (!step.isScrollToElement) {
|
|
111
|
-
// absolute scroll
|
|
112
|
-
return Promise.each(step.events, event => {
|
|
113
|
-
let start, end;
|
|
114
|
-
if (step.isGranularScroll) {
|
|
115
|
-
({start, end} = this.getScrollCoordinatesFromSwipe(event, target));
|
|
116
|
-
} else {
|
|
117
|
-
// scroll entire page per event
|
|
118
|
-
const direction = AndroidScrollStepAction.getDirection(event);
|
|
119
|
-
({ start, end } = AndroidScrollStepAction.getScrollCoordinatesFromPageScroll(target, direction, 0.9));
|
|
120
|
-
}
|
|
121
|
-
return this.driver.scroll(start, end, step.scrollDuration);
|
|
122
|
-
}).then(() => {
|
|
123
|
-
return {success: true};
|
|
124
|
-
});
|
|
125
|
-
}
|
|
126
|
-
|
|
127
|
-
this.step.scrollToElement.targetId = "scroll-to-element";
|
|
128
|
-
const scrollDirection = this.getScrollToElementDirection(step.events);
|
|
129
|
-
return this.scrollToElement(step, target, scrollDirection);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
|
|
133
|
-
module.exports = AndroidScrollStepAction;
|
|
134
|
-
|
|
@@ -1,22 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const StepAction = require('../../stepAction');
|
|
4
|
-
|
|
5
|
-
const ALLOWED_KEY_CODE_NAME = ['normal', 'unspecified', 'none', 'go', 'search', 'send', 'next', 'done', 'previous'];
|
|
6
|
-
|
|
7
|
-
class AndroidSpecialKeyStepAction extends StepAction {
|
|
8
|
-
performAction() {
|
|
9
|
-
const {step} = this;
|
|
10
|
-
const action = this.getActionKeyCodeName(step.keyCodeName);
|
|
11
|
-
|
|
12
|
-
return this.driver.executeImeAction(action);
|
|
13
|
-
}
|
|
14
|
-
|
|
15
|
-
getActionKeyCodeName(keyCodeName) {
|
|
16
|
-
const lowerKeyCodeName = keyCodeName.toLowerCase();
|
|
17
|
-
return ALLOWED_KEY_CODE_NAME.includes(lowerKeyCodeName) ? lowerKeyCodeName : 'go';
|
|
18
|
-
}
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
module.exports = AndroidSpecialKeyStepAction;
|
|
22
|
-
|
|
@@ -1,32 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const StepAction = require('../../stepAction');
|
|
4
|
-
|
|
5
|
-
const normalizePercent = (percent) => {
|
|
6
|
-
const percentCeiling = Math.min(percent, 0.99);
|
|
7
|
-
const percentFloor = Math.max(percentCeiling, 0.01);
|
|
8
|
-
return percentFloor;
|
|
9
|
-
};
|
|
10
|
-
|
|
11
|
-
class AndroidSwipeStepAction extends StepAction {
|
|
12
|
-
|
|
13
|
-
static getSwipeCoordinates(target, event) {
|
|
14
|
-
const { rect } = target;
|
|
15
|
-
const { elementPositionTouchDown, elementPositionTouchUp } = event;
|
|
16
|
-
const startX = (rect.width * normalizePercent(elementPositionTouchDown.percentX)) + rect.left;
|
|
17
|
-
const startY = (rect.height * normalizePercent(elementPositionTouchDown.percentY)) + rect.top;
|
|
18
|
-
|
|
19
|
-
const endX = (rect.width * normalizePercent(elementPositionTouchUp.percentX)) + rect.left;
|
|
20
|
-
const endY = (rect.height * normalizePercent(elementPositionTouchUp.percentY)) + rect.top;
|
|
21
|
-
|
|
22
|
-
return {start: {x: startX, y: startY}, end: {x: endX, y: endY}};
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
performAction() {
|
|
26
|
-
const { start, end} = AndroidSwipeStepAction.getSwipeCoordinates(this.getTarget(), this.step.events[0]);
|
|
27
|
-
return this.driver.swipe(start, end, this.step.swipeDuration);
|
|
28
|
-
}
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
module.exports = AndroidSwipeStepAction;
|
|
32
|
-
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const StepAction = require('../stepAction');
|
|
4
|
-
class AndroidGlobalActionStepAction extends StepAction {
|
|
5
|
-
|
|
6
|
-
performAction() {
|
|
7
|
-
return this.driver.pressKeycode(this.step.keyCode);
|
|
8
|
-
}
|
|
9
|
-
}
|
|
10
|
-
|
|
11
|
-
module.exports = AndroidGlobalActionStepAction;
|
|
12
|
-
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const StepAction = require('../stepAction');
|
|
4
|
-
|
|
5
|
-
class AndroidTapStepAction extends StepAction {
|
|
6
|
-
|
|
7
|
-
performAction() {
|
|
8
|
-
const {appiumSelector, rect} = this.getTarget();
|
|
9
|
-
if (this.step.isTouch) {
|
|
10
|
-
const positionX = parseInt(rect.left + (rect.width * this.step.relativeTouch.percentX));
|
|
11
|
-
const positionY = parseInt(rect.top + (rect.height * this.step.relativeTouch.percentY));
|
|
12
|
-
return this.driver.touch(positionX, positionY);
|
|
13
|
-
}
|
|
14
|
-
return this.driver.tap(appiumSelector);
|
|
15
|
-
}
|
|
16
|
-
}
|
|
17
|
-
|
|
18
|
-
module.exports = AndroidTapStepAction;
|
|
19
|
-
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const StepAction = require('../stepAction');
|
|
4
|
-
const sessionPlayer = require('../../../commons/getSessionPlayerRequire');
|
|
5
|
-
const paramEvaluator = sessionPlayer.stepParamExpressionEvaluator;
|
|
6
|
-
|
|
7
|
-
class AndroidTextChangeStepAction extends StepAction {
|
|
8
|
-
|
|
9
|
-
computeExpression(stepActionFactory) {
|
|
10
|
-
if (paramEvaluator) {
|
|
11
|
-
return paramEvaluator.computeExpressionPromise(this.step.expression, context, this.exportsGlobal, this.exportsTest);
|
|
12
|
-
}
|
|
13
|
-
return stepActionFactory.executeStep(this.step.expression, this.context, this.frameHandler, this.exportsGlobal, null, this.exportsTest)
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
performAction(stepActionFactory) {
|
|
17
|
-
return this.computeExpression(stepActionFactory)
|
|
18
|
-
.then(res => this.driver.setText(this.getTarget().seleniumElement, res.evaluatedText));
|
|
19
|
-
}
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
module.exports = AndroidTextChangeStepAction;
|
|
23
|
-
|
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
"use strict";
|
|
2
|
-
|
|
3
|
-
const StepAction = require('../../stepAction');
|
|
4
|
-
const sessionPlayer = require('../../../../commons/getSessionPlayerRequire');
|
|
5
|
-
const mobileUtils = sessionPlayer.mobileUtils;
|
|
6
|
-
const { getElementAttributesMap, getXPathSelector } = require('appium-dom-utils');
|
|
7
|
-
const logger = require('../../../../commons/logger').getLogger("ios-locate-step-action");
|
|
8
|
-
|
|
9
|
-
const { JSDOM, VirtualConsole } = require('jsdom');
|
|
10
|
-
|
|
11
|
-
function createUtils(driver) {
|
|
12
|
-
return class {
|
|
13
|
-
static getFrameIdByTestimFrameId() {}
|
|
14
|
-
|
|
15
|
-
static setElementResultDataOnContext(target, result) {
|
|
16
|
-
const { dom, element, success } = result;
|
|
17
|
-
if (!success) {
|
|
18
|
-
return Promise.resolve();
|
|
19
|
-
}
|
|
20
|
-
const selector = getXPathSelector(element);
|
|
21
|
-
if (!selector) {
|
|
22
|
-
return Promise.reject(new Error('Could not build iOS selector'));
|
|
23
|
-
}
|
|
24
|
-
target.appiumSelector = selector.replace('/AppiumAUT', '');
|
|
25
|
-
|
|
26
|
-
const attributes = getElementAttributesMap(element);
|
|
27
|
-
delete attributes["testim_dom_element_id"];
|
|
28
|
-
target.attributes = attributes;
|
|
29
|
-
|
|
30
|
-
return driver.getElementBySelector(target.appiumSelector)
|
|
31
|
-
.then(seleniumResponse => {
|
|
32
|
-
return target.seleniumElement = seleniumResponse.value
|
|
33
|
-
});
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
static getElementRectangle(target) {
|
|
37
|
-
if (mobileUtils) {
|
|
38
|
-
const {attributes} = target;
|
|
39
|
-
const {x, y, width, height} = mobileUtils.getIosRect(attributes);
|
|
40
|
-
return Promise.resolve({left: x, top: y, width, height});
|
|
41
|
-
}
|
|
42
|
-
return driver.getElementRect(target);
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
static getOffsets() {
|
|
46
|
-
return Promise.resolve([]);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
static htmlStringToDom(htmlString, url) {
|
|
50
|
-
|
|
51
|
-
const virtualConsole = new VirtualConsole();
|
|
52
|
-
const jsdom = new JSDOM(htmlString, {
|
|
53
|
-
virtualConsole,
|
|
54
|
-
features: {
|
|
55
|
-
FetchExternalResources: ["script", "frame", "iframe", "link", "img"]
|
|
56
|
-
},
|
|
57
|
-
contentType: "text/xml"
|
|
58
|
-
}) || {};
|
|
59
|
-
|
|
60
|
-
const {document} = jsdom.window;
|
|
61
|
-
process.nextTick(() => {
|
|
62
|
-
jsdom.window.close();
|
|
63
|
-
});
|
|
64
|
-
document.TESTIM_URL = url;
|
|
65
|
-
var elements = Array.from(document.querySelectorAll("*"));
|
|
66
|
-
elements.forEach(function (element, index) {
|
|
67
|
-
element.setAttribute("testim_dom_element_id", index);
|
|
68
|
-
});
|
|
69
|
-
return document;
|
|
70
|
-
}
|
|
71
|
-
|
|
72
|
-
static isVisible(target) {
|
|
73
|
-
if (target.seleniumElement) {
|
|
74
|
-
return Promise.resolve(true);
|
|
75
|
-
}
|
|
76
|
-
return Promise.resolve(false);
|
|
77
|
-
}
|
|
78
|
-
};
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
class IosLocateStepAction extends StepAction {
|
|
83
|
-
execute() {
|
|
84
|
-
return this.driver.getSource()
|
|
85
|
-
.then(res => Promise.resolve({html: res.value}));
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
static getUtils(driver) {
|
|
89
|
-
return createUtils(driver);
|
|
90
|
-
}
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
static getFrameIdByTestimFrameId(...args) {
|
|
94
|
-
logger.warn('Unplanned access to getFrameIdByTestimFrameId() #Android');
|
|
95
|
-
throw new Error('Use .getUtils() instead');
|
|
96
|
-
}
|
|
97
|
-
|
|
98
|
-
static setElementResultDataOnContext(...args) {
|
|
99
|
-
logger.warn('Unplanned access to setElementResultDataOnContext() #Android');
|
|
100
|
-
throw new Error('Use .getUtils() instead');
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
static getElementRectangle(...args) {
|
|
104
|
-
logger.warn('Unplanned access to getElementRectangle() #Android');
|
|
105
|
-
throw new Error('Use .getUtils() instead');
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
static getOffsets(...args) {
|
|
109
|
-
logger.warn('Unplanned access to getOffsets() #Android');
|
|
110
|
-
throw new Error('Use .getUtils() instead');
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
static htmlStringToDom(...args) {
|
|
114
|
-
logger.warn('Unplanned access to htmlStringToDom() #Android');
|
|
115
|
-
throw new Error('Use .getUtils() instead');
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
static isVisible(...args) {
|
|
119
|
-
logger.warn('Unplanned access to isVisible() #Android');
|
|
120
|
-
throw new Error('Use .getUtils() instead');
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
|
|
124
|
-
module.exports = IosLocateStepAction;
|
|
@@ -1,76 +0,0 @@
|
|
|
1
|
-
const StepAction = require('../../stepAction');
|
|
2
|
-
const Directions = { Up: "scroll_up", Down: "scroll_down", Left: "scroll_left", Right: "scroll_right", };
|
|
3
|
-
const logger = require('../../../../commons/logger').getLogger('ios-scroll-step-action');
|
|
4
|
-
const sessionPlayer = require('../../../../commons/getSessionPlayerRequire');
|
|
5
|
-
const constants = sessionPlayer.commonConstants.stepResult;
|
|
6
|
-
|
|
7
|
-
class IosScrollStepAction extends StepAction {
|
|
8
|
-
performAction() {
|
|
9
|
-
const {step} = this;
|
|
10
|
-
const target = this.getTarget();
|
|
11
|
-
|
|
12
|
-
if (!step.isScrollToElement) {
|
|
13
|
-
throw new Error('absolute scroll not supported on iOS');
|
|
14
|
-
}
|
|
15
|
-
|
|
16
|
-
step.scrollToElement.targetId = "scroll-to-element";
|
|
17
|
-
const scrollDirection = step.direction;
|
|
18
|
-
return this.scrollToElement(step, target, scrollDirection);
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
scrollToElement(step, scrolledOnElementTarget, scrollDirection) {
|
|
22
|
-
const runTimeout = this.context.data.timeToPlayStep;
|
|
23
|
-
const runMaxTime = Date.now() + runTimeout;
|
|
24
|
-
return this.locateElementPlayer.findElements([this.step.scrollToElement], step, this.frameHandler)
|
|
25
|
-
.catch((err) => {
|
|
26
|
-
const { start, end } = this.getScrollCoordinatesFromPageScroll(scrolledOnElementTarget, scrollDirection);
|
|
27
|
-
if (Date.now() > runMaxTime) {
|
|
28
|
-
logger.log("Scroll to element reached timeout")
|
|
29
|
-
throw Object.assign(new Error("Scroll timeout reached:" + err.message), {
|
|
30
|
-
id: this.step.id,
|
|
31
|
-
success: false,
|
|
32
|
-
shouldRetry: true,
|
|
33
|
-
isTimeout: true,
|
|
34
|
-
errorType: constants.ACTION_TIMEOUT
|
|
35
|
-
});
|
|
36
|
-
}
|
|
37
|
-
return this.driver.scroll(start, end)
|
|
38
|
-
.then(() => this.scrollToElement(step, scrolledOnElementTarget, scrollDirection));
|
|
39
|
-
});
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
getScrollCoordinatesFromPageScroll(target, direction, offsetFromStart = 0.75) {
|
|
43
|
-
const {rect} = target;
|
|
44
|
-
const smallOffset = 5;
|
|
45
|
-
let startX, startY, endX, endY;
|
|
46
|
-
switch (direction) {
|
|
47
|
-
case Directions.Down:
|
|
48
|
-
startX = 0;
|
|
49
|
-
startY = rect.top + (rect.height * offsetFromStart);
|
|
50
|
-
endX = 0;
|
|
51
|
-
endY = rect.top + smallOffset;
|
|
52
|
-
break;
|
|
53
|
-
case Directions.Up:
|
|
54
|
-
startX = 0;
|
|
55
|
-
startY = rect.top + (rect.height * (1 - offsetFromStart));
|
|
56
|
-
endX = 0;
|
|
57
|
-
endY = rect.top + rect.height - smallOffset;
|
|
58
|
-
break;
|
|
59
|
-
case Directions.Right:
|
|
60
|
-
startX = rect.left + (rect.width * offsetFromStart);
|
|
61
|
-
startY = 0;
|
|
62
|
-
endX = rect.left + smallOffset;
|
|
63
|
-
endY = 0;
|
|
64
|
-
break;
|
|
65
|
-
case Directions.Left:
|
|
66
|
-
startX = rect.left + (rect.width * (1 - offsetFromStart));
|
|
67
|
-
startY = 0;
|
|
68
|
-
endX = rect.left + rect.width - smallOffset;
|
|
69
|
-
endY = 0;
|
|
70
|
-
break;
|
|
71
|
-
}
|
|
72
|
-
return {start: {x: startX, y: startY}, end: {x: endX, y: endY}};
|
|
73
|
-
}
|
|
74
|
-
}
|
|
75
|
-
|
|
76
|
-
module.exports = IosScrollStepAction;
|