@testim/testim-cli 3.230.0 → 3.233.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/cli.js +6 -0
- package/commons/featureFlags.js +1 -1
- package/commons/httpRequest.js +4 -3
- package/commons/testimCloudflare.js +73 -0
- package/commons/testimServicesApi.js +34 -0
- package/commons/testimTunnel.js +18 -2
- package/npm-shrinkwrap.json +394 -322
- package/package.json +1 -1
- package/player/WebDriverHttpRequest.js +1 -1
- package/player/stepActions/scripts/scroll.js +12 -2
- package/player/stepActions/scrollStepAction.js +1 -1
- package/player/stepActions/stepActionRegistrar.js +0 -4
- package/player/utils/eyeSdkService.js +21 -2
- package/runOptions.js +21 -0
- package/runner.js +1 -1
- package/runners/TestPlanRunner.js +8 -5
- package/services/gridService.js +1 -1
- package/services/lambdatestService.js +2 -1
- package/player/stepActions/salesforceAutoLoginStepAction.js +0 -39
package/package.json
CHANGED
|
@@ -154,7 +154,7 @@ class WebDriverHttpRequest {
|
|
|
154
154
|
httpDeleteRequest(path) {
|
|
155
155
|
const requestId = utils.guid();
|
|
156
156
|
logger.info("DELETE REQUEST", {requestId, path, testResultId: this.testResultId});
|
|
157
|
-
return httpRequest.deleteFullRes(`${this.gridUrl}${path}`, this.headers, this.connectionRetryTimeout)
|
|
157
|
+
return httpRequest.deleteFullRes(`${this.gridUrl}${path}`, undefined, this.headers, this.connectionRetryTimeout)
|
|
158
158
|
.tap((response) => logger.info("DELETE RESPONSE", {
|
|
159
159
|
requestId,
|
|
160
160
|
path,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var scroll = function (elementToScrollOn, elementToScrollTo, isScrollToElement, expectedX, expectedY, shouldScrollLeft, shouldScrollTop) {
|
|
2
|
+
var scroll = function (elementToScrollOn, elementToScrollTo, isScrollToElement, isDynamicScroll, expectedX, expectedY, shouldScrollLeft, shouldScrollTop) {
|
|
3
3
|
|
|
4
4
|
function doScroll(expectedPosition, element) {
|
|
5
5
|
if (!element) {
|
|
@@ -21,6 +21,11 @@ var scroll = function (elementToScrollOn, elementToScrollTo, isScrollToElement,
|
|
|
21
21
|
}
|
|
22
22
|
|
|
23
23
|
var target = getLocatedElement(locatedElement);
|
|
24
|
+
|
|
25
|
+
if (isDynamicScroll && !target) {
|
|
26
|
+
return { x: parentElement.scrollWidth, y: parentElement.scrollHeight };
|
|
27
|
+
}
|
|
28
|
+
|
|
24
29
|
if(!target) {
|
|
25
30
|
throw new Error('could not find target element');
|
|
26
31
|
}
|
|
@@ -63,8 +68,13 @@ var scroll = function (elementToScrollOn, elementToScrollTo, isScrollToElement,
|
|
|
63
68
|
|
|
64
69
|
var actualXString = result.actualX;
|
|
65
70
|
var actualYString = result.actualY;
|
|
71
|
+
var actualScrollToElement = getLocatedElement(elementToScrollTo);
|
|
72
|
+
|
|
73
|
+
if (isScrollToElement && isDynamicScroll && !actualScrollToElement) {
|
|
74
|
+
return { success: false, expectedPosition };
|
|
75
|
+
}
|
|
76
|
+
|
|
66
77
|
if (isScrollToElement) {
|
|
67
|
-
var actualScrollToElement = getLocatedElement(elementToScrollTo);
|
|
68
78
|
if (!actualScrollToElement) {
|
|
69
79
|
throw new Error('could not find target to scroll to');
|
|
70
80
|
}
|
|
@@ -38,7 +38,7 @@ class ScrollStepAction extends StepAction {
|
|
|
38
38
|
return scroll.apply(null, arguments)
|
|
39
39
|
`;
|
|
40
40
|
|
|
41
|
-
return this.driver.executeJSWithArray(scrollCode, [elementToScrollOn, elementToScrollTo,
|
|
41
|
+
return this.driver.executeJSWithArray(scrollCode, [elementToScrollOn, elementToScrollTo, Boolean(step.isScrollToElement), Boolean(step.isDynamicScroll), expectedX, expectedY, step.shouldScrollLeft, step.shouldScrollTop])
|
|
42
42
|
.then((res) => {
|
|
43
43
|
if(!res || !res.value) {
|
|
44
44
|
return {
|
|
@@ -23,8 +23,6 @@ const ExtractTextStepAction = require('./extractTextStepAction');
|
|
|
23
23
|
const TdkHybridStepAction = require('./tdkHybridStepAction');
|
|
24
24
|
const PixelValidationStepAction = require('./pixelValidationStepAction');
|
|
25
25
|
|
|
26
|
-
const SalesforceAutoLoginStepAction = require('./salesforceAutoLoginStepAction');
|
|
27
|
-
|
|
28
26
|
const CliJsStepAction = require('./cliJsStepAction');
|
|
29
27
|
const CliConditionStepAction = require('./cliConditionStepAction');
|
|
30
28
|
const NodePackageStepAction = require('./nodePackageStepAction');
|
|
@@ -84,8 +82,6 @@ module.exports = function (driver, stepActionFactory, runMode) {
|
|
|
84
82
|
'email-code-step': JsCodeStepAction,
|
|
85
83
|
'cli-email-code-step': CliJsStepAction,
|
|
86
84
|
'tdk-hybrid': TdkHybridStepAction,
|
|
87
|
-
|
|
88
|
-
'salesforce-autologin': SalesforceAutoLoginStepAction,
|
|
89
85
|
};
|
|
90
86
|
|
|
91
87
|
register(STEP_ACTION_MAPPING, stepActionFactory);
|
|
@@ -8,7 +8,24 @@ const { EyeSdkBuilder } = require('../../commons/getSessionPlayerRequire');
|
|
|
8
8
|
const { makeSDK } = require('@applitools/eyes-sdk-core');
|
|
9
9
|
const { W3C_ELEMENT_ID } = require('../constants');
|
|
10
10
|
const _ = require('lodash');
|
|
11
|
-
|
|
11
|
+
|
|
12
|
+
let packageJson;
|
|
13
|
+
// There is a difference in the folder structure in prod vs. dev
|
|
14
|
+
try {
|
|
15
|
+
// PRODUCTION
|
|
16
|
+
// eslint-disable-next-line import/no-unresolved
|
|
17
|
+
packageJson = require('../../package.json');
|
|
18
|
+
} catch (e) {
|
|
19
|
+
//pass
|
|
20
|
+
}
|
|
21
|
+
if (!packageJson) {
|
|
22
|
+
try {
|
|
23
|
+
// in dev, they are one level up
|
|
24
|
+
packageJson = require('../../../package.json');
|
|
25
|
+
} catch (e) {
|
|
26
|
+
//pass
|
|
27
|
+
}
|
|
28
|
+
}
|
|
12
29
|
|
|
13
30
|
const LEGACY_ELEMENT_ID = 'ELEMENT';
|
|
14
31
|
|
|
@@ -218,10 +235,12 @@ class EyesSpec {
|
|
|
218
235
|
|
|
219
236
|
class EyeSdkService {
|
|
220
237
|
constructor() {
|
|
238
|
+
const sdkVersion = packageJson ? packageJson.dependencies['@applitools/eyes-sdk-core'] : 'N/A';
|
|
239
|
+
|
|
221
240
|
/** @type {Core} */
|
|
222
241
|
this.sdk = makeSDK({
|
|
223
242
|
name: 'Testim.io',
|
|
224
|
-
version: `4.0.0/eyes-sdk-core/${
|
|
243
|
+
version: `4.0.0/eyes-sdk-core/${sdkVersion}`,
|
|
225
244
|
spec: new EyesSpec(),
|
|
226
245
|
VisualGridClient: require('@applitools/visual-grid-client'),
|
|
227
246
|
});
|
package/runOptions.js
CHANGED
|
@@ -295,7 +295,9 @@ program
|
|
|
295
295
|
.option('--require-credentials', 'Log in to Testim if not already logged in')
|
|
296
296
|
|
|
297
297
|
// Tunnel
|
|
298
|
+
.option('tunneld', 'run a tunnel daemon only')
|
|
298
299
|
.option('--tunnel [tunnel]', 'enable tunnel')
|
|
300
|
+
.option('--tunnel-routes [routes]', 'tunnel routes for cloudflare tunnels')
|
|
299
301
|
.option('--tunnel-port [tunnel-port]', 'tunnel port address')
|
|
300
302
|
.option('--tunnel-host-header [tunnel-host-header]', 'tunnel host header')
|
|
301
303
|
.option('--tunnel-region [tunnel-region]', 'ngrok tunnel region')
|
|
@@ -522,6 +524,23 @@ module.exports = {
|
|
|
522
524
|
throw err;
|
|
523
525
|
}
|
|
524
526
|
|
|
527
|
+
if (program.tunneld) {
|
|
528
|
+
return {
|
|
529
|
+
tunnel: true,
|
|
530
|
+
tunnelPort: program.tunnelPort,
|
|
531
|
+
tunnelRoutes: program.tunnelRoutes,
|
|
532
|
+
tunnelRoutesOutput: program.tunnelRoutesOutput,
|
|
533
|
+
tunnelHostHeader: program.tunnelHostHeader,
|
|
534
|
+
tunnelRegion: program.tunnelRegion,
|
|
535
|
+
tunnelDiagnostics: program.tunnelDiagnostics,
|
|
536
|
+
tunnelUseHttpAddress: program.tunnelUseHttpAddress,
|
|
537
|
+
tunnelOnlyMode: true,
|
|
538
|
+
token: program.token,
|
|
539
|
+
project: program.project,
|
|
540
|
+
};
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
|
|
525
544
|
const isTestConfigSpecified = (program.testConfig && program.testConfig.length) || (program.testConfigId && program.testConfigId.length);
|
|
526
545
|
const isTestPlanSpecified = (program.testPlan && program.testPlan.length) || (program.testPlanId && program.testPlanId.length);
|
|
527
546
|
const isSuiteSpecified = (program.suite && program.suite.length) || (program.suiteId && program.suiteId.length);
|
|
@@ -1108,6 +1127,8 @@ module.exports = {
|
|
|
1108
1127
|
// Tunnel
|
|
1109
1128
|
tunnel: program.tunnel,
|
|
1110
1129
|
tunnelPort: program.tunnelPort,
|
|
1130
|
+
tunnelRoutes: program.tunnelRoutes,
|
|
1131
|
+
tunnelRoutesOutput: program.tunnelRoutesOutput,
|
|
1111
1132
|
tunnelHostHeader: program.tunnelHostHeader,
|
|
1112
1133
|
tunnelRegion: program.tunnelRegion,
|
|
1113
1134
|
tunnelDiagnostics: program.tunnelDiagnostics,
|
package/runner.js
CHANGED
|
@@ -213,7 +213,7 @@ function runRunner(options, customExtensionLocalLocation) {
|
|
|
213
213
|
|
|
214
214
|
return validateCliAccount(options)
|
|
215
215
|
.log('in runRunner before tunnel.connect')
|
|
216
|
-
.then(() => tunnel.connect(options
|
|
216
|
+
.then(() => tunnel.connect(options))
|
|
217
217
|
.log('in runRunner after tunnel.connect')
|
|
218
218
|
.then(() => new TestPlanRunner(customExtensionLocalLocation).run(options))
|
|
219
219
|
.log('before tunnel.disconnect')
|
|
@@ -79,7 +79,7 @@ class TestPlanRunner {
|
|
|
79
79
|
throw err;
|
|
80
80
|
})
|
|
81
81
|
.finally(async () => {
|
|
82
|
-
if ((tpOptions.lightweightMode && tpOptions.lightweightMode.disablePixelValidation)
|
|
82
|
+
if ((tpOptions.lightweightMode && tpOptions.lightweightMode.disablePixelValidation)) {
|
|
83
83
|
return;
|
|
84
84
|
}
|
|
85
85
|
// When sessionPlayer is available, use it - as it only attempts to close batches that exist.
|
|
@@ -88,22 +88,25 @@ class TestPlanRunner {
|
|
|
88
88
|
await EyeSdkBuilder.closeBatch(executionId);
|
|
89
89
|
return;
|
|
90
90
|
}
|
|
91
|
+
/** @type {Awaited<ReturnType<typeof testimServicesApi['getApplitoolsIntegrationData']>>} */
|
|
92
|
+
let applitoolsIntegrationData;
|
|
91
93
|
try {
|
|
92
94
|
if (!tpOptions.company || !tpOptions.company.activePlan || !tpOptions.company.activePlan.premiumFeatures || !tpOptions.company.activePlan.premiumFeatures.applitools) {
|
|
93
95
|
return;
|
|
94
96
|
}
|
|
95
|
-
|
|
96
|
-
if (_.isEmpty(applitoolsIntegrationData)) {
|
|
97
|
+
applitoolsIntegrationData = await testimServicesApi.getApplitoolsIntegrationData(tpOptions.project);
|
|
98
|
+
if (_.isEmpty(applitoolsIntegrationData) || !executionId) {
|
|
97
99
|
return;
|
|
98
100
|
}
|
|
99
101
|
const { runKey: apiKey, url: serverUrl } = applitoolsIntegrationData;
|
|
100
102
|
const tmpSDK = require('@applitools/eyes-sdk-core').makeSDK({ name: 'Testim.io', version: '4.0.0', spec: {} });
|
|
101
103
|
await tmpSDK.closeBatches({ batchIds: [executionId], serverUrl, apiKey });
|
|
102
104
|
} catch (err) {
|
|
103
|
-
|
|
105
|
+
// If a batch with this name did not exist, do not log an error.
|
|
106
|
+
if (err.message && (err.message.startsWith('Request failed with status code 404') || err.message.startsWith('no batchIds were set'))) {
|
|
104
107
|
return;
|
|
105
108
|
}
|
|
106
|
-
logger.error('Failed closing batch in extension mode', { err, projectId: tpOptions.project });
|
|
109
|
+
logger.error('Failed closing batch in extension mode', { err, projectId: tpOptions.project, applitoolsIntegrationData, batchIds: [executionId] });
|
|
107
110
|
}
|
|
108
111
|
});
|
|
109
112
|
}
|
package/services/gridService.js
CHANGED
|
@@ -258,7 +258,7 @@ async function getGridData(options) {
|
|
|
258
258
|
if (grid) {
|
|
259
259
|
return getGridDataByGridName(companyId, grid, allGrids);
|
|
260
260
|
}
|
|
261
|
-
if (hasTestPlanFlag(options)) {
|
|
261
|
+
if (hasTestPlanFlag(options) || options.tunnelOnlyMode) {
|
|
262
262
|
logger.info('skipping getting grid, as it is set on test plan', { companyId });
|
|
263
263
|
return undefined;
|
|
264
264
|
}
|
|
@@ -13,6 +13,7 @@ const httpRequest = require('../commons/httpRequest');
|
|
|
13
13
|
const { ArgError } = require('../errors');
|
|
14
14
|
const servicesApi = require('../commons/testimServicesApi');
|
|
15
15
|
const { getExtensionsUrl } = require('../runOptionsUtils');
|
|
16
|
+
const featureFlagService = require('../commons/featureFlags');
|
|
16
17
|
|
|
17
18
|
const logger = require('../commons/logger').getLogger('lambdatestService');
|
|
18
19
|
|
|
@@ -215,7 +216,7 @@ class LambdatestService {
|
|
|
215
216
|
console: true,
|
|
216
217
|
queueTimeout: 300, // time a session spends in the LT queue, in seconds (apparently 300 is the minimum)
|
|
217
218
|
// visual: true, // [NOTE]: activate LT screenshots feature (can slow test).
|
|
218
|
-
|
|
219
|
+
network: featureFlagService.flags.LTNetworkCapabilities.isEnabled(), // [NOTE]: activate LT capture network logs feature (can cause network issues).
|
|
219
220
|
// fixedIP: '10.80.34.143', // [NOTE]: this is for debug purposes with LT team.
|
|
220
221
|
};
|
|
221
222
|
}
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
const NavigationStepAction = require('./navigationStepAction');
|
|
2
|
-
const Promise = require('bluebird');
|
|
3
|
-
|
|
4
|
-
class SalesforceAutoLoginStepAction extends NavigationStepAction {
|
|
5
|
-
async performAction() {
|
|
6
|
-
let salesforceUrl = this.context.data.testimNavigationStepDestination || this.context.data.url;
|
|
7
|
-
try {
|
|
8
|
-
salesforceUrl = await this.updateBaseUrl(salesforceUrl);
|
|
9
|
-
await this.driver.url(salesforceUrl);
|
|
10
|
-
await Promise.delay(5000); // wait a little for the page to load (fixes screenshots and clicking on elements in username verification screen)
|
|
11
|
-
let newUrl = await this.driver.getUrl();
|
|
12
|
-
// Verify username screen
|
|
13
|
-
const isUsernameVerificationNeeded = newUrl.includes(this.step.USERNAME_VERIFICATION_PATH_ID);
|
|
14
|
-
const timeout = this.context.data.timeToPlayStep + 3000;
|
|
15
|
-
if (isUsernameVerificationNeeded) {
|
|
16
|
-
await this.driver.executeCodeAsync(`
|
|
17
|
-
function ${this.step.handleUsernameVerificationAUTFunc.toString()}
|
|
18
|
-
handleUsernameVerificationAUTFunc();
|
|
19
|
-
var done = arguments[1];
|
|
20
|
-
done();
|
|
21
|
-
`, timeout);
|
|
22
|
-
await Promise.delay(5000);
|
|
23
|
-
newUrl = await this.driver.getUrl(); // If we managed to continue correctly we want to get the new redirected url
|
|
24
|
-
}
|
|
25
|
-
await Promise.delay(1500);
|
|
26
|
-
return {
|
|
27
|
-
success: true,
|
|
28
|
-
newUrl,
|
|
29
|
-
};
|
|
30
|
-
} catch (err) {
|
|
31
|
-
return {
|
|
32
|
-
success: false,
|
|
33
|
-
reason: err.message,
|
|
34
|
-
};
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
module.exports = SalesforceAutoLoginStepAction;
|