@testim/testim-cli 3.251.0 → 3.253.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/agent/routers/index.js +2 -1
- package/agent/routers/playground/router.js +1 -1
- package/commons/chrome-launcher.js +6 -6
- package/commons/constants.js +2 -0
- package/commons/getSessionPlayerRequire.js +2 -20
- package/commons/initializeUserWithAuth.js +2 -2
- package/commons/mockNetworkRuleFileSchema.json +40 -38
- package/commons/testimDesiredCapabilitiesBuilder.js +43 -0
- package/commons/testimServicesApi.js +11 -2
- package/credentialsManager.js +17 -20
- package/npm-shrinkwrap.json +2104 -444
- package/package.json +4 -2
- package/player/WebdriverioWebDriverApi.js +7 -2
- package/player/appiumTestPlayer.js +102 -0
- package/player/seleniumTestPlayer.js +3 -2
- package/player/services/frameLocator.js +2 -1
- package/player/services/mobileFrameLocatorMock.js +32 -0
- package/player/services/playbackTimeoutCalculator.js +1 -0
- package/player/services/portSelector.js +10 -8
- package/player/services/tabService.js +29 -0
- package/player/stepActions/sfdcRecordedStepAction.js +2 -2
- package/player/stepActions/sfdcStepAction.js +2 -2
- package/player/stepActions/stepAction.js +15 -1
- package/player/utils/stepActionUtils.js +4 -2
- package/player/utils/windowUtils.js +138 -125
- package/player/webdriver.js +39 -25
- package/reports/debugReporter.js +41 -39
- package/reports/jsonReporter.js +53 -50
- package/reports/reporter.js +135 -136
- package/runOptions.js +2 -1
- package/runners/ParallelWorkerManager.js +2 -0
- package/testRunStatus.js +457 -459
- package/workers/BaseWorker.js +13 -6
- package/workers/WorkerAppium.js +123 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@testim/testim-cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.253.0",
|
|
4
4
|
"description": "Command line interface for running Testing on your CI",
|
|
5
5
|
"author": "Oren Rubin",
|
|
6
6
|
"contributors": [{
|
|
@@ -68,6 +68,7 @@
|
|
|
68
68
|
"form-data": "3.0.0",
|
|
69
69
|
"fs-extra": "10.0.1",
|
|
70
70
|
"glob": "7.2.0",
|
|
71
|
+
"https-proxy-agent": "5.0.0",
|
|
71
72
|
"istanbul-lib-report": "3.0.0",
|
|
72
73
|
"istanbul-reports": "3.0.2",
|
|
73
74
|
"jimp": "0.16.1",
|
|
@@ -98,6 +99,7 @@
|
|
|
98
99
|
"threads": "0.12.0",
|
|
99
100
|
"ua-parser-js": "0.7.28",
|
|
100
101
|
"validate-npm-package-name": "3.0.0",
|
|
102
|
+
"webdriverio": "7.24.0",
|
|
101
103
|
"winston": "3.6.0",
|
|
102
104
|
"winston-transport": "4.5.0",
|
|
103
105
|
"ws": "8.5.0",
|
|
@@ -119,6 +121,6 @@
|
|
|
119
121
|
"pack-serve": "yarn pack-onprem && http-server deploy/"
|
|
120
122
|
},
|
|
121
123
|
"engines": {
|
|
122
|
-
"node": ">=
|
|
124
|
+
"node": ">= 14.0.0"
|
|
123
125
|
}
|
|
124
126
|
}
|
|
@@ -5,7 +5,7 @@ const Queue = require('promise-queue');
|
|
|
5
5
|
const Promise = require('bluebird');
|
|
6
6
|
const config = require('../commons/config');
|
|
7
7
|
const {
|
|
8
|
-
UNICODE_CHARACTERS, W3C_ELEMENT_ID,
|
|
8
|
+
UNICODE_CHARACTERS, W3C_ELEMENT_ID,
|
|
9
9
|
} = require('./constants');
|
|
10
10
|
const isElementDisplayed = require('./scripts/isElementDisplayed');
|
|
11
11
|
const logger = require('../commons/logger').getLogger('WebDriverApi');
|
|
@@ -59,6 +59,7 @@ class WebdriverioWebDriverApi {
|
|
|
59
59
|
this.queue = new Queue(maxConcurrent, maxQueue);
|
|
60
60
|
}
|
|
61
61
|
|
|
62
|
+
/** @returns {Promise<any>} */
|
|
62
63
|
addToQueue(func) {
|
|
63
64
|
const perfId = this.seleniumPerfStats.markStart();
|
|
64
65
|
return this.queue.add(func)
|
|
@@ -247,6 +248,10 @@ class WebdriverioWebDriverApi {
|
|
|
247
248
|
.finally(() => this.seleniumPerfStats.markEnd(perfId, SELENIUM_PERF_MARKS.GET_SCREENSHOT));
|
|
248
249
|
}
|
|
249
250
|
|
|
251
|
+
/**
|
|
252
|
+
* @param {string} selector
|
|
253
|
+
* @returns {Promise<{ value: HTMLElement }>}
|
|
254
|
+
*/
|
|
250
255
|
getElementBySelector(selector) {
|
|
251
256
|
return this.addToQueue(() => this.client.element(selector));
|
|
252
257
|
}
|
|
@@ -506,7 +511,7 @@ class WebdriverioWebDriverApi {
|
|
|
506
511
|
return this.addToQueue(() => this.client.getTitle());
|
|
507
512
|
}
|
|
508
513
|
|
|
509
|
-
|
|
514
|
+
// eslint-disable-next-line default-param-last
|
|
510
515
|
windowHandleSize(windowHandle = 'current', size) {
|
|
511
516
|
return this.addToQueue(() => {
|
|
512
517
|
let data = {};
|
|
@@ -0,0 +1,102 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const webdriverio = require('webdriverio');
|
|
4
|
+
const TabService = require('./services/tabService');
|
|
5
|
+
const PortSelector = require('./services/portSelector');
|
|
6
|
+
const windowCreationListener = require('./services/windowCreationListener');
|
|
7
|
+
const frameLocatorFactory = require('./services/mobileFrameLocatorMock');
|
|
8
|
+
const { isDebuggerConnected } = require('../commons/detectDebugger');
|
|
9
|
+
const logger = require('../commons/logger').getLogger('appium-test-player');
|
|
10
|
+
|
|
11
|
+
const sessionPlayer = require('../commons/getSessionPlayerRequire');
|
|
12
|
+
|
|
13
|
+
const Player = sessionPlayer.sessionPlayer;
|
|
14
|
+
// delete after https://github.com/testimio/clickim/pull/3430 release to the store
|
|
15
|
+
const assetService = sessionPlayer.assetService;
|
|
16
|
+
const commonConstants = sessionPlayer.commonConstants;
|
|
17
|
+
const StepActionFactory = sessionPlayer.stepActionFactory;
|
|
18
|
+
const mobileLocateElementPlayer = sessionPlayer.MobileLocateElementPlayer;
|
|
19
|
+
const PlaybackTimeoutCalculator = require('./services/playbackTimeoutCalculator');
|
|
20
|
+
const testResultService = require('../commons/socket/testResultService');
|
|
21
|
+
|
|
22
|
+
// delete after https://github.com/testimio/clickim/pull/3430 release to the store
|
|
23
|
+
const CryptoJS = require('crypto-js');
|
|
24
|
+
const StepActionUtils = require('./utils/stepActionUtils');
|
|
25
|
+
|
|
26
|
+
class AppiumTestPlayer {
|
|
27
|
+
//eslint-disable-next-line default-param-last
|
|
28
|
+
constructor(id, userParamsData, shouldMonitorPerformance, automationMode = 'code', driver = webdriverio, testRetryCount, previousTestResultId) {
|
|
29
|
+
this.driver = driver;
|
|
30
|
+
this.id = id;
|
|
31
|
+
|
|
32
|
+
const stepActionUtils = new StepActionUtils(this.driver);
|
|
33
|
+
this.stepActionFactory = new StepActionFactory(stepActionUtils);
|
|
34
|
+
require('./stepActions/stepActionRegistrar')(this.driver, this.stepActionFactory, 'selenium');
|
|
35
|
+
|
|
36
|
+
if (assetService.setMd5) {
|
|
37
|
+
// delete after https://github.com/testimio/clickim/pull/3430 release to the store
|
|
38
|
+
assetService.setMd5(CryptoJS);
|
|
39
|
+
}
|
|
40
|
+
this.tabService = new TabService(this.driver);
|
|
41
|
+
this.windowCreationListener = windowCreationListener;
|
|
42
|
+
this.playbackTimeoutCalculator = new PlaybackTimeoutCalculator(isDebuggerConnected());
|
|
43
|
+
|
|
44
|
+
this.tabService.createSesion(id);
|
|
45
|
+
|
|
46
|
+
const FrameLocator = frameLocatorFactory(this.driver);
|
|
47
|
+
|
|
48
|
+
this.sessionPlayer = new Player(
|
|
49
|
+
id,
|
|
50
|
+
this.tabService,
|
|
51
|
+
null,
|
|
52
|
+
null,
|
|
53
|
+
FrameLocator,
|
|
54
|
+
PortSelector,
|
|
55
|
+
mobileLocateElementPlayer,
|
|
56
|
+
null /* Not in use, placeholder for the order of arguments */,
|
|
57
|
+
stepActionUtils,
|
|
58
|
+
this.stepActionFactory,
|
|
59
|
+
this.playbackTimeoutCalculator,
|
|
60
|
+
testResultService.getSocket(),
|
|
61
|
+
automationMode,
|
|
62
|
+
);
|
|
63
|
+
|
|
64
|
+
if (this.sessionPlayer.setShouldMonitorPerformance) {
|
|
65
|
+
this.sessionPlayer.setShouldMonitorPerformance(shouldMonitorPerformance);
|
|
66
|
+
}
|
|
67
|
+
this.sessionPlayer.playbackManager.isRemoteSession = true;
|
|
68
|
+
this.sessionPlayer.playbackManager.isLocalRun = false;
|
|
69
|
+
this.sessionPlayer.playbackManager.testRetryCount = testRetryCount;
|
|
70
|
+
this.sessionPlayer.playbackManager.previousTestResultId = previousTestResultId;
|
|
71
|
+
|
|
72
|
+
this.sessionPlayer.playbackManager.userParamsData = userParamsData || {};
|
|
73
|
+
this.onStepCompleted = this.onStepCompleted.bind(this);
|
|
74
|
+
|
|
75
|
+
this.sessionPlayer.playbackManager.on(commonConstants.playback.RESULT, this.onStepCompleted);
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
onStepCompleted(result, testId, resultId, step) {
|
|
79
|
+
//do nothing for now ...
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
|
|
83
|
+
async onDone() {
|
|
84
|
+
try {
|
|
85
|
+
await this.driver.activeSession.deleteSession();
|
|
86
|
+
} catch (error) {
|
|
87
|
+
logger.error('error while deleting appium session', { error });
|
|
88
|
+
} finally {
|
|
89
|
+
this.sessionPlayer.playbackManager.off(commonConstants.playback.RESULT);
|
|
90
|
+
this.sessionPlayer = null;
|
|
91
|
+
this.tabService = null;
|
|
92
|
+
this.stepActionFactory = null;
|
|
93
|
+
this.driver = null;
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
getSessionId() {
|
|
98
|
+
return this.driver.activeSession.sessionId;
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
module.exports = AppiumTestPlayer;
|
|
@@ -10,7 +10,7 @@ const { isDebuggerConnected } = require('../commons/detectDebugger');
|
|
|
10
10
|
|
|
11
11
|
const sessionPlayer = require('../commons/getSessionPlayerRequire');
|
|
12
12
|
|
|
13
|
-
const
|
|
13
|
+
const Player = sessionPlayer.sessionPlayer;
|
|
14
14
|
// delete after https://github.com/testimio/clickim/pull/3430 release to the store
|
|
15
15
|
const assetService = sessionPlayer.assetService;
|
|
16
16
|
const commonConstants = sessionPlayer.commonConstants;
|
|
@@ -24,6 +24,7 @@ const CryptoJS = require('crypto-js');
|
|
|
24
24
|
const StepActionUtils = require('./utils/stepActionUtils');
|
|
25
25
|
|
|
26
26
|
class SeleniumTestPlayer {
|
|
27
|
+
//eslint-disable-next-line default-param-last
|
|
27
28
|
constructor(id, userParamsData, shouldMonitorPerformance, automationMode = 'code', driver = new WebDriver(), testRetryCount, previousTestResultId) {
|
|
28
29
|
this.driver = driver;
|
|
29
30
|
this.id = id;
|
|
@@ -47,7 +48,7 @@ class SeleniumTestPlayer {
|
|
|
47
48
|
|
|
48
49
|
const FrameLocator = frameLocatorFactory(this.driver);
|
|
49
50
|
|
|
50
|
-
this.sessionPlayer = new
|
|
51
|
+
this.sessionPlayer = new Player(
|
|
51
52
|
id,
|
|
52
53
|
this.tabService,
|
|
53
54
|
CookieUtils(this.driver),
|
|
@@ -19,6 +19,7 @@ const _getGuidFromSeleniumElement = (seleniumElement) => {
|
|
|
19
19
|
/** @param {import('../webdriver')} driver*/
|
|
20
20
|
module.exports = function frameLocatorFactory(driver) {
|
|
21
21
|
class FrameLocator {
|
|
22
|
+
/** @type {(...args: ConstructorParameters<typeof import('clickim/src/background/frameLocator').FrameLocator>) => this} */
|
|
22
23
|
constructor(frameManager, locateElementPlayer) {
|
|
23
24
|
this.frameManager = frameManager;
|
|
24
25
|
this.locateElementPlayer = locateElementPlayer;
|
|
@@ -34,7 +35,7 @@ module.exports = function frameLocatorFactory(driver) {
|
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
cacheFrameLocateResults(frameHandler) {
|
|
37
|
-
if (frameHandler
|
|
38
|
+
if (frameHandler?.seleniumFrameElement && frameHandler.frameLocateResultUrl) {
|
|
38
39
|
const guid = _getGuidFromSeleniumElement(frameHandler.seleniumFrameElement);
|
|
39
40
|
if (guid) {
|
|
40
41
|
this.cacheResults(guid, frameHandler.frameLocateResultUrl);
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
const logger = require('../../commons/logger').getLogger('mobile-frame-locator-mock');
|
|
4
|
+
|
|
5
|
+
/** @param {import('../webdriver')} driver*/
|
|
6
|
+
module.exports = function frameLocatorFactory(driver) {
|
|
7
|
+
class FrameLocator {
|
|
8
|
+
/** @type {(...args: ConstructorParameters<typeof import('clickim/src/background/frameLocator').FrameLocator>) => this} */
|
|
9
|
+
constructor(frameManager, locateElementPlayer) {
|
|
10
|
+
this.frameManager = frameManager;
|
|
11
|
+
this.locateElementPlayer = locateElementPlayer;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
foundFrameCallback(result, frameTree, testimFrameId) {
|
|
15
|
+
logger.info('foundFrameCallback-mock invoked');
|
|
16
|
+
return {};
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
locate(frameLocator, frameDepth, currentFrame, context, frameTree, stepData) {
|
|
21
|
+
logger.info('locate-mock invoked');
|
|
22
|
+
return {};
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
findFrame(stepData, frameLocators, context, frameTree) {
|
|
26
|
+
logger.info('findFrame-mock invoked');
|
|
27
|
+
return {};
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
return FrameLocator;
|
|
32
|
+
};
|
|
@@ -1,16 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
2
3
|
const Promise = require('bluebird');
|
|
3
4
|
|
|
4
5
|
// Legacy code not supported in selenium mode
|
|
5
6
|
class PortSelector {
|
|
6
|
-
constructor
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
7
|
+
// eslint-disable-next-line no-useless-constructor, no-empty-function
|
|
8
|
+
constructor() { }
|
|
9
|
+
select() {
|
|
10
|
+
// eslint-disable-next-line no-console
|
|
11
|
+
console.log('\n\t\t\tinternal error - cant use port selector in selenium!!!!\n');
|
|
12
|
+
// eslint-disable-next-line prefer-promise-reject-errors
|
|
13
|
+
return Promise.reject({ reason: 'cant use port selector in selenium!' });
|
|
12
14
|
}
|
|
13
|
-
prepare(){}
|
|
15
|
+
prepare() {}
|
|
14
16
|
handleLegacyDataCaching() {}
|
|
15
17
|
}
|
|
16
18
|
|
|
@@ -15,12 +15,41 @@ const constants = sessionPlayer.commonConstants.stepResult;
|
|
|
15
15
|
const tabMatcher = sessionPlayer.tabMatcher;
|
|
16
16
|
const logger = require('../../commons/logger').getLogger('tab-service');
|
|
17
17
|
|
|
18
|
+
/**
|
|
19
|
+
* @typedef {{
|
|
20
|
+
* attachDebugger(): Promise<any>,
|
|
21
|
+
* detachDebugger(): Promise<any>,
|
|
22
|
+
* onDebuggerDetached(): {},
|
|
23
|
+
* tabId: string,
|
|
24
|
+
* domUtils: { getDOM(): Promise<any> },
|
|
25
|
+
* windowUtils: WindowUtils,
|
|
26
|
+
* imageCaptureUtils: ImageCaptureUtils
|
|
27
|
+
* }} TabUtil
|
|
28
|
+
* */
|
|
29
|
+
/**
|
|
30
|
+
* @typedef {{
|
|
31
|
+
* infoId: any;
|
|
32
|
+
* url: any;
|
|
33
|
+
* title: any;
|
|
34
|
+
* favIconUrl: any;
|
|
35
|
+
* order: any;
|
|
36
|
+
* from: any;
|
|
37
|
+
* isMain: any;
|
|
38
|
+
* openerStepId: any;
|
|
39
|
+
* }} TabInfo
|
|
40
|
+
*/
|
|
41
|
+
|
|
18
42
|
class TabService {
|
|
43
|
+
/** @param {import('../webdriver')} driver */
|
|
19
44
|
constructor(driver) {
|
|
20
45
|
this.driver = driver;
|
|
46
|
+
/** @type {Record<string, TabUtil>} */
|
|
21
47
|
this._utils = {};
|
|
48
|
+
/** @type {Record<string, { tabCount: number; tabInfos: Record<string, TabInfo> }>} */
|
|
22
49
|
this.sessionTabs = {};
|
|
50
|
+
/** @type {Record<string, string>} */
|
|
23
51
|
this.pendingTabs = {};
|
|
52
|
+
/** @type {Record<string, Set<any>>} */
|
|
24
53
|
this.addedTabs = {};
|
|
25
54
|
}
|
|
26
55
|
|
|
@@ -5,8 +5,8 @@ class SfdcRecordedStepAction extends StepAction {
|
|
|
5
5
|
async performAction() {
|
|
6
6
|
const page = sfdc.sfdcNewSePage(this.driver);
|
|
7
7
|
try {
|
|
8
|
-
await sfdc.sfdcExecuteRecordedStep(page, this.step.recordedData);
|
|
9
|
-
return { success: true };
|
|
8
|
+
const warnings = await sfdc.sfdcExecuteRecordedStep(page, this.step.recordedData, this.context);
|
|
9
|
+
return { success: true, reason: warnings };
|
|
10
10
|
} catch (err) {
|
|
11
11
|
return {
|
|
12
12
|
success: false,
|
|
@@ -9,8 +9,8 @@ class SfdcStepAction extends StepAction {
|
|
|
9
9
|
if (actions === undefined) {
|
|
10
10
|
throw new Error('No test actions were compiled');
|
|
11
11
|
}
|
|
12
|
-
await sfdc.sfdcExecute(page, actions);
|
|
13
|
-
return { success: true };
|
|
12
|
+
const warnings = await sfdc.sfdcExecute(page, actions, this.context);
|
|
13
|
+
return { success: true, reason: warnings };
|
|
14
14
|
} catch (err) {
|
|
15
15
|
return {
|
|
16
16
|
success: false,
|
|
@@ -3,8 +3,21 @@
|
|
|
3
3
|
const { commonConstants } = require('../../commons/getSessionPlayerRequire');
|
|
4
4
|
const Promise = require('bluebird');
|
|
5
5
|
|
|
6
|
+
/** @typedef {typeof import('clickim/src/background/stepActions/stepAction').StepAction} ClickimStepActionCtor */
|
|
7
|
+
/** @typedef {ConstructorParameters<ClickimStepActionCtor>} ClickimStepActionCtorParams */
|
|
8
|
+
/** @typedef {InstanceType<ClickimStepActionCtor>} ClickimStepAction */
|
|
9
|
+
|
|
6
10
|
class StepAction {
|
|
7
|
-
|
|
11
|
+
/** @type {(...args: ClickimStepActionCtorParams) => this} */
|
|
12
|
+
constructor(
|
|
13
|
+
step,
|
|
14
|
+
context,
|
|
15
|
+
frameHandler,
|
|
16
|
+
exportsGlobal = {},
|
|
17
|
+
stepActionUtils = undefined,
|
|
18
|
+
locateElementPlayer = undefined,
|
|
19
|
+
exportsTest = {},
|
|
20
|
+
) {
|
|
8
21
|
this.step = step;
|
|
9
22
|
this.context = context;
|
|
10
23
|
this.frameHandler = frameHandler;
|
|
@@ -28,6 +41,7 @@ class StepAction {
|
|
|
28
41
|
return this.context.data[targetId];
|
|
29
42
|
}
|
|
30
43
|
|
|
44
|
+
/** @type {ClickimStepAction['execute']} */
|
|
31
45
|
execute(stepActionFactory, step) {
|
|
32
46
|
return Promise.resolve(this.performAction(stepActionFactory, step))
|
|
33
47
|
.then(res => Promise.resolve(Object.assign({}, { success: true }, res)))
|
|
@@ -4,6 +4,7 @@ const { locatorBuilderUtils, utils, codeSnippets } = sessionPlayer;
|
|
|
4
4
|
const CookieUtils = require('./cookieUtils');
|
|
5
5
|
|
|
6
6
|
class StepActionUtils {
|
|
7
|
+
/** @param {import('../webdriver')} driver */
|
|
7
8
|
constructor(driver, cookieUtils) {
|
|
8
9
|
this.driver = driver;
|
|
9
10
|
this._abortedSteps = [];
|
|
@@ -63,8 +64,9 @@ class StepActionUtils {
|
|
|
63
64
|
return this.driver.getElementTextJS(locatedElement);
|
|
64
65
|
}
|
|
65
66
|
|
|
66
|
-
|
|
67
|
-
|
|
67
|
+
/** @type {import('clickim/src/background/stepActions/stepActionUtils').StepActionUtils['markDynamicParent']} */
|
|
68
|
+
async markDynamicParent(target, id, frameHandler) {
|
|
69
|
+
return this.driver.markDynamicParent(target, id, frameHandler);
|
|
68
70
|
}
|
|
69
71
|
|
|
70
72
|
getCookie(name) {
|