@testim/testim-cli 3.261.0 → 3.262.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/commons/testimServicesApi.js +10 -7
- package/executionQueue.js +9 -1
- package/npm-shrinkwrap.json +2 -2
- package/package.json +1 -1
- package/player/stepActions/RefreshStepAction.js +7 -4
- package/player/stepActions/baseJsStepAction.js +45 -46
- package/player/stepActions/dropFileStepAction.js +11 -12
- package/player/stepActions/evaluateExpressionStepAction.js +32 -33
- package/player/stepActions/extensionOnlyStepAction.js +3 -4
- package/player/stepActions/extractTextStepAction.js +8 -10
- package/player/stepActions/hoverStepAction.js +3 -3
- package/player/stepActions/locateStepAction.js +39 -34
- package/player/stepActions/mouseStepAction.js +36 -34
- package/player/stepActions/navigationStepAction.js +7 -8
- package/player/stepActions/scrollStepAction.js +22 -22
- package/player/stepActions/stepAction.js +21 -21
- package/player/stepActions/stepActionRegistrar.js +63 -58
- package/player/stepActions/submitStepAction.js +2 -3
- package/player/stepActions/textStepAction.js +14 -14
- package/player/stepActions/textValidationStepAction.js +50 -38
- package/player/stepActions/wheelStepAction.js +5 -11
- package/processHandler.js +2 -0
- package/reports/junitReporter.js +18 -1
- package/runOptions.d.ts +4 -0
- package/runOptions.js +8 -1
- package/runners/TestPlanRunner.js +20 -19
- package/runners/runnerUtils.js +1 -2
- package/testRunHandler.js +18 -9
- package/testRunStatus.js +205 -157
- package/workers/BaseWorker.js +11 -0
- package/workers/WorkerExtension.js +117 -91
- package/workers/WorkerSelenium.js +8 -3
|
@@ -183,6 +183,14 @@ function reportExecutionFinished(status, executionId, projectId, success, tmsOpt
|
|
|
183
183
|
}), { retries: DEFAULT_REQUEST_RETRY });
|
|
184
184
|
}
|
|
185
185
|
|
|
186
|
+
/**
|
|
187
|
+
* @param {string} projectId
|
|
188
|
+
* @param {string[]} names
|
|
189
|
+
* @param {string[]} planIds
|
|
190
|
+
* @param {string} branch
|
|
191
|
+
* @param {import('../runOptions').RunnerOptions['intersections']} intersections
|
|
192
|
+
* @returns {ReturnType<import('services/src/test-plan/service')['testPlan']['getTestPlanTestList']>}
|
|
193
|
+
*/
|
|
186
194
|
async function getTestPlanTestList(projectId, names, planIds, branch, intersections) {
|
|
187
195
|
return pRetry(() => postAuth({
|
|
188
196
|
url: '/testPlan/list',
|
|
@@ -206,12 +214,7 @@ async function getTestPlanTestList(projectId, names, planIds, branch, intersecti
|
|
|
206
214
|
* testConfigIds?: string[];
|
|
207
215
|
* intersections: import('../runOptions').RunnerOptions['intersections'];
|
|
208
216
|
* }} param0
|
|
209
|
-
* @returns {
|
|
210
|
-
* tests: any[][];
|
|
211
|
-
* branch?: string;
|
|
212
|
-
* runName?: string;
|
|
213
|
-
* runExists?: boolean;
|
|
214
|
-
* }>}
|
|
217
|
+
* @returns {import('services/src/suite/service').RunListResult}
|
|
215
218
|
*/
|
|
216
219
|
function getSuiteTestList({
|
|
217
220
|
projectId, labels, testIds, testNames, testConfigNames, suiteNames, suiteIds, branch, rerunFailedByRunId, testConfigIds, intersections,
|
|
@@ -247,7 +250,7 @@ function isTestResultCompleted(resultId, projectId, testRetryKey) {
|
|
|
247
250
|
}
|
|
248
251
|
|
|
249
252
|
function getTestResults(testId, resultId, projectId, branch) {
|
|
250
|
-
return pRetry(() => getWithAuth(`/test/v2/${testId}/result/${resultId}`, { projectId, branch }), { retries: DEFAULT_REQUEST_RETRY });
|
|
253
|
+
return pRetry(() => getWithAuth(`/test/v2/${testId}/result/${resultId}`, { projectId, branch }), { retries: DEFAULT_REQUEST_RETRY, factor: 1 });
|
|
251
254
|
}
|
|
252
255
|
|
|
253
256
|
function keepAliveGrid(projectId, slots) {
|
package/executionQueue.js
CHANGED
|
@@ -1,8 +1,16 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const TestRun = require('./testRunHandler
|
|
3
|
+
const TestRun = require('./testRunHandler');
|
|
4
4
|
|
|
5
5
|
class ExecutionQueue {
|
|
6
|
+
/**
|
|
7
|
+
* @param {string} executionId
|
|
8
|
+
* @param {string} executionName
|
|
9
|
+
* @param {any[]} testList
|
|
10
|
+
* @param {import('./runOptions').RunnerOptions} options
|
|
11
|
+
* @param {string} branchToUse
|
|
12
|
+
* @param {import('./testRunStatus')} testRunStatus
|
|
13
|
+
*/
|
|
6
14
|
constructor(executionId, executionName, testList, options, branchToUse, testStatus) {
|
|
7
15
|
this._waitingTests = testList.map(testInfo => new TestRun(executionId, executionName, testInfo, options, branchToUse, testStatus));
|
|
8
16
|
}
|
package/npm-shrinkwrap.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@testim/testim-cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.262.0",
|
|
4
4
|
"lockfileVersion": 2,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@testim/testim-cli",
|
|
9
|
-
"version": "3.
|
|
9
|
+
"version": "3.262.0",
|
|
10
10
|
"license": "Proprietary",
|
|
11
11
|
"dependencies": {
|
|
12
12
|
"@applitools/eyes-sdk-core": "13.6.23",
|
package/package.json
CHANGED
|
@@ -4,10 +4,13 @@ const StepAction = require('./stepAction');
|
|
|
4
4
|
require('bluebird');
|
|
5
5
|
|
|
6
6
|
class RefreshStepAction extends StepAction {
|
|
7
|
-
execute() {
|
|
8
|
-
|
|
9
|
-
.
|
|
10
|
-
|
|
7
|
+
async execute() {
|
|
8
|
+
try {
|
|
9
|
+
await this.driver.reloadTab();
|
|
10
|
+
return { success: true };
|
|
11
|
+
} catch (error) {
|
|
12
|
+
return { success: false, reason: error.message };
|
|
13
|
+
}
|
|
11
14
|
}
|
|
12
15
|
}
|
|
13
16
|
|
|
@@ -15,6 +15,7 @@ const constants = commonConstants.stepResult;
|
|
|
15
15
|
const logger = require('../../commons/logger').getLogger('base-js-step-action');
|
|
16
16
|
|
|
17
17
|
const _ = require('lodash');
|
|
18
|
+
const utils = require('../../utils');
|
|
18
19
|
|
|
19
20
|
function constructWithArguments(constructor, args) {
|
|
20
21
|
function F() {
|
|
@@ -98,46 +99,43 @@ class BaseJsStepAction extends StepAction {
|
|
|
98
99
|
const that = this;
|
|
99
100
|
const retryInterval = that.context.config.retryTimeout;
|
|
100
101
|
let timeToPlayStep = that.context.data.timeToPlayStep - retryInterval;
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
}
|
|
126
|
-
if (res.status && res.status === 'failed') {
|
|
127
|
-
return resolve({ success: false, shouldRetry: true, result: res.result });
|
|
128
|
-
}
|
|
129
|
-
if (timeToPlayStep - retryInterval > 0) {
|
|
130
|
-
timeToPlayStep -= retryInterval;
|
|
131
|
-
setTimeout(checkScriptStatus, retryInterval);
|
|
132
|
-
} else {
|
|
133
|
-
return resolve(Object.assign({}, res, { success: false, shouldRetry: true }));
|
|
134
|
-
}
|
|
135
|
-
return undefined;
|
|
136
|
-
});
|
|
102
|
+
async function checkScriptStatus() {
|
|
103
|
+
let selRes;
|
|
104
|
+
try {
|
|
105
|
+
selRes = await that.executeGetStatus(transactionId);
|
|
106
|
+
} catch (err) {
|
|
107
|
+
logger.warn('failed to get js status', { err });
|
|
108
|
+
selRes = { value: { status: 'exception' } };
|
|
109
|
+
}
|
|
110
|
+
let res;
|
|
111
|
+
try {
|
|
112
|
+
res = JSON.parse(selRes ? selRes.value : '{}');
|
|
113
|
+
} catch (e) {
|
|
114
|
+
logger.warn('non object value', { selRes });
|
|
115
|
+
res = { status: 'exception' };
|
|
116
|
+
}
|
|
117
|
+
const abortReason = that.stepActionUtils.abortedSteps.find(abortedStep => abortedStep.id === that.step.id);
|
|
118
|
+
if (abortReason) {
|
|
119
|
+
return abortReason;
|
|
120
|
+
}
|
|
121
|
+
if (!res) {
|
|
122
|
+
return { success: true };
|
|
123
|
+
}
|
|
124
|
+
if (res.status && res.status === 'done') {
|
|
125
|
+
return res;
|
|
137
126
|
}
|
|
127
|
+
if (res.status && res.status === 'failed') {
|
|
128
|
+
return { success: false, shouldRetry: true, result: res.result };
|
|
129
|
+
}
|
|
130
|
+
if (timeToPlayStep - retryInterval <= 0) {
|
|
131
|
+
return Object.assign(res, { success: false, shouldRetry: true });
|
|
132
|
+
}
|
|
133
|
+
timeToPlayStep -= retryInterval;
|
|
134
|
+
await utils.delay(retryInterval);
|
|
135
|
+
return checkScriptStatus();
|
|
136
|
+
}
|
|
138
137
|
|
|
139
|
-
|
|
140
|
-
});
|
|
138
|
+
return checkScriptStatus();
|
|
141
139
|
}
|
|
142
140
|
|
|
143
141
|
executeInAut(eventMessage) {
|
|
@@ -241,7 +239,7 @@ class BaseJsStepAction extends StepAction {
|
|
|
241
239
|
return resp?.success ? this.codeExecDone(resp) : this.codeExecFailed(resp);
|
|
242
240
|
}
|
|
243
241
|
|
|
244
|
-
performAction() {
|
|
242
|
+
async performAction() {
|
|
245
243
|
const step = this.step;
|
|
246
244
|
const context = this.context;
|
|
247
245
|
|
|
@@ -262,14 +260,15 @@ class BaseJsStepAction extends StepAction {
|
|
|
262
260
|
testResultId: context.testResultId,
|
|
263
261
|
};
|
|
264
262
|
|
|
263
|
+
const browserAndOS = await this.driver.getBrowserAndOS();
|
|
264
|
+
Object.assign(eventMessage, { browser: browserAndOS.browser, browserMajor: browserAndOS.browserMajor });
|
|
265
|
+
|
|
266
|
+
if (!this.context.isPendingPromise) {
|
|
267
|
+
await this.executeInAut(eventMessage);
|
|
268
|
+
}
|
|
265
269
|
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
Object.assign(eventMessage, { browser: browserAndOS.browser, browserMajor: browserAndOS.browserMajor });
|
|
269
|
-
return this.context.isPendingPromise ? undefined : this.executeInAut(eventMessage);
|
|
270
|
-
})
|
|
271
|
-
.then(() => this.checkStatus(eventMessage.transactionId))
|
|
272
|
-
.then(resp => this.checkCodeResponse(resp));
|
|
270
|
+
const resp = await this.checkStatus(eventMessage.transactionId);
|
|
271
|
+
return await this.checkCodeResponse(resp);
|
|
273
272
|
}
|
|
274
273
|
|
|
275
274
|
handleExecutionError(err) {
|
|
@@ -8,26 +8,25 @@ const { codeSnippets, utils } = require('../../commons/getSessionPlayerRequire')
|
|
|
8
8
|
const featureFlagService = require('../../commons/featureFlags');
|
|
9
9
|
|
|
10
10
|
class DropFileStepAction extends StepAction {
|
|
11
|
-
performAction() {
|
|
11
|
+
async performAction() {
|
|
12
12
|
const target = this.context.data[this.step.targetId || 'targetId'];
|
|
13
13
|
const overrideAzureStorageUrl = featureFlagService.flags.overrideAzureStorageUrl.isEnabled();
|
|
14
|
-
|
|
15
|
-
return (utils.addTokenToFileUrl ? utils.addTokenToFileUrl(
|
|
14
|
+
const fileUrls = await utils.addTokenToFileUrl(
|
|
16
15
|
this.context.project.id,
|
|
17
16
|
this.step.fileUrls,
|
|
18
17
|
this.stepActionUtils.testimServicesApi,
|
|
19
18
|
overrideAzureStorageUrl,
|
|
20
19
|
logger,
|
|
21
|
-
)
|
|
22
|
-
const dropFileCode = `
|
|
23
|
-
var getLocatedElement = ${codeSnippets.getLocatedElementCode};
|
|
24
|
-
var createDropEvent = ${(codeSnippets.createDropEvent ? codeSnippets.createDropEvent : createDropEventLegacy).toString()};
|
|
25
|
-
var downloadFileAndFireDropEvent = ${downloadFileAndFireDropEvent.toString()};
|
|
26
|
-
return downloadFileAndFireDropEvent.apply(null, arguments)
|
|
27
|
-
`;
|
|
20
|
+
);
|
|
28
21
|
|
|
29
|
-
|
|
30
|
-
}
|
|
22
|
+
const dropFileCode = `
|
|
23
|
+
var getLocatedElement = ${codeSnippets.getLocatedElementCode};
|
|
24
|
+
var createDropEvent = ${(codeSnippets.createDropEvent ? codeSnippets.createDropEvent : createDropEventLegacy).toString()};
|
|
25
|
+
var downloadFileAndFireDropEvent = ${downloadFileAndFireDropEvent.toString()};
|
|
26
|
+
return downloadFileAndFireDropEvent.apply(null, arguments)
|
|
27
|
+
`;
|
|
28
|
+
|
|
29
|
+
return await this.driver.executeJSWithArray(dropFileCode, [target.locatedElement, fileUrls]);
|
|
31
30
|
}
|
|
32
31
|
}
|
|
33
32
|
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
'use strict';
|
|
2
2
|
|
|
3
|
-
const Promise = require('bluebird');
|
|
4
3
|
const sessionPlayer = require('../../commons/getSessionPlayerRequire');
|
|
5
4
|
const StepAction = require('./stepAction');
|
|
6
5
|
|
|
@@ -10,44 +9,44 @@ const logger = require('../../commons/logger').getLogger('evaluate-expression-st
|
|
|
10
9
|
const _ = require('lodash');
|
|
11
10
|
|
|
12
11
|
class EvaluateExpressionStepAction extends StepAction {
|
|
13
|
-
execute() {
|
|
12
|
+
async execute() {
|
|
14
13
|
const step = this.step;
|
|
15
14
|
const context = this.context;
|
|
16
15
|
const exportsGlobal = this.exportsGlobal;
|
|
17
16
|
const exportsTest = this.exportsTest;
|
|
18
17
|
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
incomingParams = stepParamBuilder.getStepInputs(step, context, exportsGlobal, exportsTest);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
const params = ['context', ...incomingParams.as.functionParameters];
|
|
28
|
-
const args = [context, ...incomingParams.as.functionArguments];
|
|
29
|
-
const expressionToEvaluate = step.subType === 'text' ? `'${step.expression.replace(/'/g, "\\\'")}'` : step.expression;
|
|
30
|
-
const code = (`return ${expressionToEvaluate}`).replace(/\n/g, '\\n');
|
|
31
|
-
const textEvaluateFunction = Function.apply(Function, params.concat([code]));
|
|
32
|
-
const evaluatedText = textEvaluateFunction.apply(null, args);
|
|
33
|
-
|
|
34
|
-
context.data[step.targetName] = evaluatedText;
|
|
35
|
-
context.data[step.targetId] = evaluatedText;
|
|
36
|
-
if (context.internalParams) {
|
|
37
|
-
context.internalParams.add(step.targetId);
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
const result = {
|
|
41
|
-
success: true,
|
|
42
|
-
evaluatedText,
|
|
43
|
-
data: context.data,
|
|
44
|
-
};
|
|
45
|
-
|
|
46
|
-
resolve(result);
|
|
47
|
-
} catch (e) {
|
|
48
|
-
reject({ errorType: constants.EVALUATE_EXPRESSION_EXCEPTION, resultInfo: { exception: e.toString() }, success: false });
|
|
18
|
+
try {
|
|
19
|
+
logger.info('runner running incoming params evaluation');
|
|
20
|
+
let incomingParams = context.incomingParams || {};
|
|
21
|
+
if (_.isEmpty(incomingParams)) {
|
|
22
|
+
incomingParams = stepParamBuilder.getStepInputs(step, context, exportsGlobal, exportsTest);
|
|
49
23
|
}
|
|
50
|
-
|
|
24
|
+
|
|
25
|
+
const params = ['context', ...incomingParams.as.functionParameters];
|
|
26
|
+
const args = [context, ...incomingParams.as.functionArguments];
|
|
27
|
+
const expressionToEvaluate = step.subType === 'text' ? `'${step.expression.replace(/'/g, "\\\'")}'` : step.expression;
|
|
28
|
+
const code = `return ${expressionToEvaluate}`.replace(/\n/g, '\\n');
|
|
29
|
+
const textEvaluateFunction = Function.apply(Function, params.concat([code]));
|
|
30
|
+
const evaluatedText = textEvaluateFunction.apply(null, args);
|
|
31
|
+
|
|
32
|
+
context.data[step.targetName] = evaluatedText;
|
|
33
|
+
context.data[step.targetId] = evaluatedText;
|
|
34
|
+
if (context.internalParams) {
|
|
35
|
+
context.internalParams.add(step.targetId);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
const result = {
|
|
39
|
+
success: true,
|
|
40
|
+
evaluatedText,
|
|
41
|
+
data: context.data,
|
|
42
|
+
};
|
|
43
|
+
|
|
44
|
+
return result;
|
|
45
|
+
} catch (e) {
|
|
46
|
+
// TODO: Fix throwing non-error
|
|
47
|
+
// eslint-disable-next-line no-throw-literal
|
|
48
|
+
throw { errorType: constants.EVALUATE_EXPRESSION_EXCEPTION, resultInfo: { exception: e.toString() }, success: false };
|
|
49
|
+
}
|
|
51
50
|
}
|
|
52
51
|
}
|
|
53
52
|
|
|
@@ -1,12 +1,11 @@
|
|
|
1
1
|
const StepAction = require('./stepAction');
|
|
2
|
-
const Promise = require('bluebird');
|
|
3
2
|
|
|
4
3
|
class ExtensionOnlyStepAction extends StepAction {
|
|
5
|
-
performAction() {
|
|
6
|
-
return
|
|
4
|
+
async performAction() {
|
|
5
|
+
return {
|
|
7
6
|
success: 'skipped',
|
|
8
7
|
reason: 'This step can run only on Chrome',
|
|
9
|
-
}
|
|
8
|
+
};
|
|
10
9
|
}
|
|
11
10
|
}
|
|
12
11
|
|
|
@@ -3,18 +3,16 @@
|
|
|
3
3
|
const StepAction = require('./stepAction');
|
|
4
4
|
|
|
5
5
|
class ExtractTextStepAction extends StepAction {
|
|
6
|
-
performAction() {
|
|
6
|
+
async performAction() {
|
|
7
7
|
const paramName = this.step.extractTextParamName;
|
|
8
8
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
};
|
|
17
|
-
});
|
|
9
|
+
const extractedText = await this.stepActionUtils.extractTargetText(this.getTarget());
|
|
10
|
+
this.context.data.exports = this.context.data.exports || {};
|
|
11
|
+
this.context.data.exports[paramName] = extractedText;
|
|
12
|
+
return {
|
|
13
|
+
success: true,
|
|
14
|
+
data: this.context.data,
|
|
15
|
+
};
|
|
18
16
|
}
|
|
19
17
|
}
|
|
20
18
|
|
|
@@ -21,7 +21,7 @@ class HoverStepAction extends StepAction {
|
|
|
21
21
|
this.getTarget().rect;
|
|
22
22
|
}
|
|
23
23
|
|
|
24
|
-
performAction() {
|
|
24
|
+
async performAction() {
|
|
25
25
|
const target = this.getTarget();
|
|
26
26
|
const { seleniumElement, rectWithoutFrameOffset, rect } = target;
|
|
27
27
|
|
|
@@ -49,8 +49,8 @@ class HoverStepAction extends StepAction {
|
|
|
49
49
|
clickOffset: { x: Math.floor(clickOffsetX), y: Math.floor(clickOffsetY) },
|
|
50
50
|
};
|
|
51
51
|
|
|
52
|
-
|
|
53
|
-
|
|
52
|
+
await this.driver.hover(seleniumElement, offsets);
|
|
53
|
+
return { success: true };
|
|
54
54
|
}
|
|
55
55
|
}
|
|
56
56
|
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
'use strict';
|
|
2
4
|
|
|
3
5
|
const StepAction = require('./stepAction');
|
|
@@ -14,15 +16,16 @@ const {
|
|
|
14
16
|
|
|
15
17
|
const DEFAULT_VISIBILITY_RESULT = { opacity: 1, clientRects: {} };
|
|
16
18
|
|
|
19
|
+
/**
|
|
20
|
+
* @param {import('../webdriver')} driver
|
|
21
|
+
*/
|
|
17
22
|
function createUtils(driver) {
|
|
18
23
|
return {
|
|
19
24
|
getFrameIdByTestimFrameId() { },
|
|
20
25
|
|
|
21
|
-
setElementResultDataOnContext(target) {
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
target.seleniumElement = seleniumResponse.value;
|
|
25
|
-
});
|
|
26
|
+
async setElementResultDataOnContext(target) {
|
|
27
|
+
const seleniumResponse = await driver.getElement(target.locatedElement);
|
|
28
|
+
target.seleniumElement = seleniumResponse.value;
|
|
26
29
|
},
|
|
27
30
|
|
|
28
31
|
getElementRectangle(target) {
|
|
@@ -76,14 +79,18 @@ function createUtils(driver) {
|
|
|
76
79
|
},
|
|
77
80
|
|
|
78
81
|
/** @type {typeof import('clickim/src/background/stepActions/locateStepAction').LocateStepAction['isVisible']} */
|
|
79
|
-
isVisible(target, targetElement, rect, locateStep, frameHandler, allOffsets, dom) {
|
|
80
|
-
const skipVisibilityCheck =
|
|
81
|
-
featureFlags.flags.disableEdgeVisibilityChecks.isEnabled() && driver.isEdge();
|
|
82
|
+
async isVisible(target, targetElement, rect, locateStep, frameHandler, allOffsets, dom) {
|
|
83
|
+
const skipVisibilityCheck = featureFlags.flags.disableEdgeVisibilityChecks.isEnabled() && driver.isEdge();
|
|
82
84
|
|
|
83
85
|
if (skipVisibilityCheck) {
|
|
84
86
|
logger.info('bypassed visibility check because of feature flag');
|
|
85
87
|
target.visibilityCheckSkipped = skipVisibilityCheck;
|
|
86
|
-
|
|
88
|
+
try {
|
|
89
|
+
await driver.isVisible(target.seleniumElement);
|
|
90
|
+
} catch {
|
|
91
|
+
/* ignored */
|
|
92
|
+
}
|
|
93
|
+
return true;
|
|
87
94
|
}
|
|
88
95
|
|
|
89
96
|
const useNativeVisibilityCheck = this.shouldUseNativeVisibilityCheck(locateStep, driver, visibilityUtils, positionUtils);
|
|
@@ -91,35 +98,33 @@ function createUtils(driver) {
|
|
|
91
98
|
return driver.isVisible(target.seleniumElement);
|
|
92
99
|
}
|
|
93
100
|
|
|
94
|
-
const handler = res => {
|
|
95
|
-
if (!targetElement || locatorBuilderUtils.isEmptyResult(targetElement)) {
|
|
96
|
-
return Promise.resolve({ visible: false, invisibleReason: 'element not found' });
|
|
97
|
-
}
|
|
98
|
-
const middlePosition = positionUtils.calculateElementMiddlePoint(rect);
|
|
99
|
-
const points = [middlePosition, positionUtils.calculateClickPoint(locateStep.clickOffset, rect)].filter(Boolean);
|
|
100
|
-
const code = codeSnippets.getVisibilityCode.getCompoundVisibilityInfoCode(target.locatedElement, points, false, locateStep);
|
|
101
|
-
return driver.execute(`return ${code}`)
|
|
102
|
-
.catch(err => {
|
|
103
|
-
logger.error('failed to execute getVisibilityCode', { err });
|
|
104
|
-
throw err;
|
|
105
|
-
})
|
|
106
|
-
.then((response = {}) => {
|
|
107
|
-
const { value: result } = response;
|
|
108
|
-
const elementVisibilityInfo = result.elementVisibilityInfo || DEFAULT_VISIBILITY_RESULT;
|
|
109
|
-
const [middleElementFromPoint, clickElementFromPoint] = result.elementsFromPointResults || [null, null];
|
|
110
|
-
|
|
111
|
-
return visibilityUtils.checkElementVisibility(elementVisibilityInfo, locateStep, clickElementFromPoint, middleElementFromPoint, dom, targetElement);
|
|
112
|
-
});
|
|
113
|
-
};
|
|
114
|
-
|
|
115
101
|
if (!target.seleniumElement) {
|
|
116
|
-
return
|
|
102
|
+
return { visible: false, invisibleReason: 'element not found' };
|
|
117
103
|
}
|
|
118
104
|
|
|
119
105
|
// this is here for the side effects.
|
|
120
|
-
|
|
121
|
-
.
|
|
122
|
-
|
|
106
|
+
try {
|
|
107
|
+
await driver.isVisible(target.seleniumElement);
|
|
108
|
+
} catch {
|
|
109
|
+
/* ignored */
|
|
110
|
+
}
|
|
111
|
+
if (!targetElement || locatorBuilderUtils.isEmptyResult(targetElement)) {
|
|
112
|
+
return { visible: false, invisibleReason: 'element not found' };
|
|
113
|
+
}
|
|
114
|
+
const middlePosition = positionUtils.calculateElementMiddlePoint(rect);
|
|
115
|
+
const points = [middlePosition, positionUtils.calculateClickPoint(locateStep.clickOffset, rect)].filter(Boolean);
|
|
116
|
+
const code = codeSnippets.getVisibilityCode.getCompoundVisibilityInfoCode(target.locatedElement, points, false, locateStep);
|
|
117
|
+
let response;
|
|
118
|
+
try {
|
|
119
|
+
response = await driver.execute(`return ${code}`);
|
|
120
|
+
} catch (err) {
|
|
121
|
+
logger.error('failed to execute getVisibilityCode', { err });
|
|
122
|
+
throw err;
|
|
123
|
+
}
|
|
124
|
+
const { value } = response || {};
|
|
125
|
+
const elementVisibilityInfo = value.elementVisibilityInfo || DEFAULT_VISIBILITY_RESULT;
|
|
126
|
+
const [middleElementFromPoint, clickElementFromPoint] = value.elementsFromPointResults || [null, null];
|
|
127
|
+
return visibilityUtils.checkElementVisibility(elementVisibilityInfo, locateStep, clickElementFromPoint, middleElementFromPoint, dom, targetElement);
|
|
123
128
|
},
|
|
124
129
|
|
|
125
130
|
scrollToElement(frameHandler, locatedElement) {
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
// @ts-check
|
|
2
|
+
|
|
1
3
|
const StepAction = require('./stepAction');
|
|
2
4
|
const html5dndAction = require('./scripts/html5dragAction');
|
|
3
5
|
const html5dndActionV2 = require('./scripts/html5dragActionV2');
|
|
@@ -22,7 +24,7 @@ class MouseStepAction extends StepAction {
|
|
|
22
24
|
};
|
|
23
25
|
}
|
|
24
26
|
|
|
25
|
-
clickJs() {
|
|
27
|
+
async clickJs() {
|
|
26
28
|
const step = this.step;
|
|
27
29
|
const context = this.context;
|
|
28
30
|
const target = context.data[step.targetId || 'targetId'];
|
|
@@ -30,7 +32,7 @@ class MouseStepAction extends StepAction {
|
|
|
30
32
|
const events = step.events;
|
|
31
33
|
|
|
32
34
|
if (!events?.length) {
|
|
33
|
-
return
|
|
35
|
+
return undefined;
|
|
34
36
|
}
|
|
35
37
|
|
|
36
38
|
const eventMessage = {
|
|
@@ -55,18 +57,19 @@ class MouseStepAction extends StepAction {
|
|
|
55
57
|
// values between 0 and -1 -_-.
|
|
56
58
|
const eventParam = this.driver.isEdge() ? JSON.stringify(eventMessage) : eventMessage;
|
|
57
59
|
|
|
58
|
-
|
|
59
|
-
.
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
60
|
+
try {
|
|
61
|
+
const result = await this.driver.executeCodeAsync(doClickCode, timeout, eventParam);
|
|
62
|
+
if (result.value?.success) {
|
|
63
|
+
return { success: true };
|
|
64
|
+
}
|
|
65
|
+
return { success: false };
|
|
66
|
+
} catch (err) {
|
|
67
|
+
return {
|
|
66
68
|
success: false,
|
|
67
69
|
reason: err.message,
|
|
68
70
|
exception: err,
|
|
69
|
-
}
|
|
71
|
+
};
|
|
72
|
+
}
|
|
70
73
|
}
|
|
71
74
|
|
|
72
75
|
isWithinBounds(start, end, point) {
|
|
@@ -126,14 +129,14 @@ class MouseStepAction extends StepAction {
|
|
|
126
129
|
this.addOffsetToEvents(this.getEventSequenceOffset());
|
|
127
130
|
}
|
|
128
131
|
|
|
129
|
-
dragPathJs() {
|
|
132
|
+
async dragPathJs() {
|
|
130
133
|
const step = this.step;
|
|
131
134
|
const context = this.context;
|
|
132
135
|
const target = context.data[step.targetId || 'targetId'];
|
|
133
136
|
const timeout = context.data.timeToPlayStep + 3000;
|
|
134
137
|
|
|
135
138
|
if (!this.step.events || !this.step.events.length) {
|
|
136
|
-
return
|
|
139
|
+
return undefined;
|
|
137
140
|
}
|
|
138
141
|
|
|
139
142
|
this.fixAbsoluteDragEventSequence();
|
|
@@ -158,18 +161,19 @@ class MouseStepAction extends StepAction {
|
|
|
158
161
|
return doDragPath.apply(null, arguments);
|
|
159
162
|
`;
|
|
160
163
|
|
|
161
|
-
|
|
162
|
-
.
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
164
|
+
try {
|
|
165
|
+
const result = await this.driver.executeCodeAsync(doDragPathCode, timeout, eventMessage);
|
|
166
|
+
if (result.value?.success) {
|
|
167
|
+
return { success: true };
|
|
168
|
+
}
|
|
169
|
+
return { success: false };
|
|
170
|
+
} catch (err) {
|
|
171
|
+
return {
|
|
169
172
|
success: false,
|
|
170
173
|
reason: err.message,
|
|
171
174
|
exception: err,
|
|
172
|
-
}
|
|
175
|
+
};
|
|
176
|
+
}
|
|
173
177
|
}
|
|
174
178
|
|
|
175
179
|
chooseAndRunAction() {
|
|
@@ -295,18 +299,16 @@ class MouseStepAction extends StepAction {
|
|
|
295
299
|
return this.driver.leftClick(seleniumElement, offsets);
|
|
296
300
|
}
|
|
297
301
|
|
|
298
|
-
performAction() {
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
return undefined;
|
|
309
|
-
});
|
|
302
|
+
async performAction() {
|
|
303
|
+
let res = await this.chooseAndRunAction();
|
|
304
|
+
if (!res.status && res.value && res.value.keep) {
|
|
305
|
+
res = res.value;
|
|
306
|
+
}
|
|
307
|
+
if (res.keep) {
|
|
308
|
+
delete res.keep;
|
|
309
|
+
return res;
|
|
310
|
+
}
|
|
311
|
+
return undefined;
|
|
310
312
|
}
|
|
311
313
|
|
|
312
314
|
addDragendIfNeeded(events) {
|