@testim/testim-cli 3.189.0 → 3.193.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 +7 -3
- package/commons/featureFlags.js +1 -0
- package/commons/runnerFileCache.js +35 -9
- package/commons/testimDesiredCapabilitiesBuilder.js +6 -1
- package/{package-lock.json → npm-shrinkwrap.json} +424 -585
- package/package.json +4 -4
- package/player/seleniumTestPlayer.js +10 -16
- package/player/stepActions/mouseStepAction.js +7 -6
- package/player/stepActions/stepAction.js +7 -10
- package/player/stepActions/stepActionRegistrar.js +58 -58
- package/runOptions.js +30 -0
- package/runner.js +5 -0
- package/runners/strategies/BaseStrategy.js +12 -6
- package/runners/strategies/LocalStrategy.js +4 -3
- package/testRunHandler.js +1 -1
- package/testRunStatus.js +5 -7
- package/workers/WorkerExtension.js +1 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@testim/testim-cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.193.0",
|
|
4
4
|
"description": "Command line interface for running Testing on your CI",
|
|
5
5
|
"author": "Oren Rubin",
|
|
6
6
|
"contributors": [{
|
|
@@ -22,7 +22,6 @@
|
|
|
22
22
|
"gulp": "4.0.2",
|
|
23
23
|
"gulp-cli": "2.3.0",
|
|
24
24
|
"gulp-json-editor": "2.5.4",
|
|
25
|
-
"gulp-mocha": "7.0.2",
|
|
26
25
|
"gulp-preprocess": "3.0.3",
|
|
27
26
|
"husky": "4.3.8",
|
|
28
27
|
"merge-stream": "2.0.0",
|
|
@@ -79,7 +78,7 @@
|
|
|
79
78
|
"istanbul-lib-report": "3.0.0",
|
|
80
79
|
"istanbul-reports": "3.0.2",
|
|
81
80
|
"jimp": "0.2.28",
|
|
82
|
-
"jsdom": "
|
|
81
|
+
"jsdom": "16.7.0",
|
|
83
82
|
"jsonwebtoken": "8.5.1",
|
|
84
83
|
"lodash": "4.17.20",
|
|
85
84
|
"memory-fs": "0.5.0",
|
|
@@ -96,7 +95,7 @@
|
|
|
96
95
|
"promise-queue": "2.2.5",
|
|
97
96
|
"prompts": "2.3.2",
|
|
98
97
|
"proxy-agent": "5.0.0",
|
|
99
|
-
"rox-node": "4.9.
|
|
98
|
+
"rox-node": "4.9.18",
|
|
100
99
|
"semver": "7.3.2",
|
|
101
100
|
"serialize-error": "7.0.1",
|
|
102
101
|
"socket.io-client": "2.4.0",
|
|
@@ -119,6 +118,7 @@
|
|
|
119
118
|
"test": "IS_UNIT_TEST=1 ./node_modules/mocha/bin/_mocha --timeout 2000 --reporter spec --exit --recursive \"./src/**/*.test.js\" --exclude ./src/codim/template.js/tests/examples/**/*.test.js",
|
|
120
119
|
"test:watch": "IS_UNIT_TEST=1 ./node_modules/mocha/bin/_mocha --timeout 2000 --exit --recursive \"./src/**/*.test.js\" --exclude ./src/codim/template.js/tests/examples/**/*.test.js --watch",
|
|
121
120
|
"test:cov": "nyc --reporter=lcov --reporter=text yarn test",
|
|
121
|
+
"upload-bundle-s3": "scripts/upload.js",
|
|
122
122
|
"prepare-version": "rm -rf ./deploy && mkdir -p deploy && gulp prepare-version-on-prem",
|
|
123
123
|
"make-onprem-deps": "cp ../../yarn.lock deploy && cd deploy && yarn install --production && bundle-deps",
|
|
124
124
|
"pack-onprem": "yarn prepare-version && yarn make-onprem-deps && cd deploy && npm pack && zip -r testim-cli.zip testim-cli-*.tgz",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
2
|
|
|
3
3
|
const TabService = require('./services/tabService');
|
|
4
4
|
const PortSelector = require('./services/portSelector');
|
|
@@ -24,9 +24,6 @@ const WebDriver = require('./webdriver');
|
|
|
24
24
|
const CryptoJS = require('crypto-js');
|
|
25
25
|
const StepActionUtils = require('./utils/stepActionUtils');
|
|
26
26
|
|
|
27
|
-
// Set JSDOM SVGElement on Global to support text validation on SVG
|
|
28
|
-
global.SVGElement = require("jsdom/lib/jsdom/living/generated/SVGSVGElement").interface;
|
|
29
|
-
|
|
30
27
|
class SeleniumTestPlayer {
|
|
31
28
|
constructor(id, userParamsData, shouldMonitorPerformance, automationMode = 'code', driver = new WebDriver(), testRetryCount, previousTestResultId) {
|
|
32
29
|
this.driver = driver;
|
|
@@ -34,7 +31,7 @@ class SeleniumTestPlayer {
|
|
|
34
31
|
|
|
35
32
|
const stepActionUtils = new StepActionUtils(this.driver);
|
|
36
33
|
this.stepActionFactory = new StepActionFactory(stepActionUtils);
|
|
37
|
-
require('./stepActions/stepActionRegistrar')(this.driver, this.stepActionFactory,
|
|
34
|
+
require('./stepActions/stepActionRegistrar')(this.driver, this.stepActionFactory, 'selenium');
|
|
38
35
|
|
|
39
36
|
if (assetService.setMd5) {
|
|
40
37
|
// delete after https://github.com/testimio/clickim/pull/3430 release to the store
|
|
@@ -74,9 +71,9 @@ class SeleniumTestPlayer {
|
|
|
74
71
|
}
|
|
75
72
|
|
|
76
73
|
onStepCompleted(result, testId, resultId, step) {
|
|
77
|
-
if(step && step.isTabOpener) {
|
|
74
|
+
if (step && step.isTabOpener) {
|
|
78
75
|
this.tabService.addNewPopup(this.id, step.id)
|
|
79
|
-
.catch(() => {});
|
|
76
|
+
.catch(() => { });
|
|
80
77
|
}
|
|
81
78
|
}
|
|
82
79
|
|
|
@@ -84,10 +81,8 @@ class SeleniumTestPlayer {
|
|
|
84
81
|
const END_DRIVER_TIMEOUT = 1000 * 60 * 2;
|
|
85
82
|
return this.driver.end()
|
|
86
83
|
.timeout(END_DRIVER_TIMEOUT)
|
|
87
|
-
.catch(Promise.TimeoutError, () =>
|
|
88
|
-
|
|
89
|
-
})
|
|
90
|
-
.catch(() => {})
|
|
84
|
+
.catch(Promise.TimeoutError, () => this.driver.forceEnd())
|
|
85
|
+
.catch(() => { })
|
|
91
86
|
.then(() => {
|
|
92
87
|
this.sessionPlayer.playbackManager.off(commonConstants.playback.RESULT, this.onStepCompleted);
|
|
93
88
|
this.sessionPlayer = null;
|
|
@@ -101,10 +96,10 @@ class SeleniumTestPlayer {
|
|
|
101
96
|
this.tabService.clearAllTabs(this.id);
|
|
102
97
|
}
|
|
103
98
|
|
|
104
|
-
addTab(openerStepId, options = { loadInfo: true}) {
|
|
99
|
+
addTab(openerStepId, options = { loadInfo: true }) {
|
|
105
100
|
return this.driver.getTabIds()
|
|
106
101
|
.tap(ids => this.tabService.addNewTab(this.id, ids[ids.length - 1], openerStepId, options))
|
|
107
|
-
.then(ids => this.sessionPlayer.addPlaybackFrameHandler(ids[ids.length - 1], undefined, {emptyPage: true}))
|
|
102
|
+
.then(ids => this.sessionPlayer.addPlaybackFrameHandler(ids[ids.length - 1], undefined, { emptyPage: true }));
|
|
108
103
|
}
|
|
109
104
|
|
|
110
105
|
async addAllTabs(openerStepId, options = { loadInfo: true, checkForMainTab: true, takeScreenshots: true }, blackList = []) {
|
|
@@ -112,14 +107,14 @@ class SeleniumTestPlayer {
|
|
|
112
107
|
// the ids are reversed so we search first in the last tab opened - otherwise it starts looking from the testim editor and not the AUT
|
|
113
108
|
|
|
114
109
|
const PROHIBITED_URLS = ['app.testim.io'].concat(blackList);
|
|
115
|
-
for(const id of ids.reverse()) {
|
|
110
|
+
for (const id of ids.reverse()) {
|
|
116
111
|
await this.tabService.addNewTab(this.id, id, openerStepId, { ...options, forceSwitch: true });
|
|
117
112
|
const tabInfo = this.tabService.getTabInfo(this.id, id);
|
|
118
113
|
if (PROHIBITED_URLS.some(bad => tabInfo.url.includes(bad))) {
|
|
119
114
|
await this.tabService.removeTabInfo(this.id, id);
|
|
120
115
|
continue;
|
|
121
116
|
}
|
|
122
|
-
await this.sessionPlayer.addPlaybackFrameHandler(id, undefined, {emptyPage: true });
|
|
117
|
+
await this.sessionPlayer.addPlaybackFrameHandler(id, undefined, { emptyPage: true });
|
|
123
118
|
}
|
|
124
119
|
if (this.tabService.tabCount(this.id) === 1) {
|
|
125
120
|
// if we only have one tab because we removed the editor tab - we have to switchTab to one of the other tabs, otherwise
|
|
@@ -130,7 +125,6 @@ class SeleniumTestPlayer {
|
|
|
130
125
|
}
|
|
131
126
|
// deal with checkForMainTab failing due to the page refreshing or JavaScript not responding or a similar issue
|
|
132
127
|
this.tabService.fixMissingMainTab(this.id);
|
|
133
|
-
|
|
134
128
|
}
|
|
135
129
|
|
|
136
130
|
getSessionId() {
|
|
@@ -111,8 +111,9 @@ class MouseStepAction extends StepAction {
|
|
|
111
111
|
this.step.events.splice(mousedownEventIndex, 0, this.generateEventOfType(downEvent, 'mouseover'));
|
|
112
112
|
}
|
|
113
113
|
|
|
114
|
-
const
|
|
115
|
-
const
|
|
114
|
+
const { recordPointerMoveEvents = false } = this.context.project.defaults || {};
|
|
115
|
+
const mouseUpEvent = this.step.events.find(event => event.event === 'mouseup') || (recordPointerMoveEvents && this.step.events.find(event => event.event === 'pointerup'));
|
|
116
|
+
const lastMouseMoveEventIndex = _.findLastIndex(this.step.events, event => event.event === 'mousemove') || (recordPointerMoveEvents && _.findLastIndex(this.step.events, event => event.event === 'pointermove'));
|
|
116
117
|
if (mouseUpEvent && lastMouseMoveEventIndex > 0 && !this.step.allEventsOnSameElement) {
|
|
117
118
|
this.step.events.splice(lastMouseMoveEventIndex + 1, 0, this.generateEventOfType(mouseUpEvent, 'mouseover'));
|
|
118
119
|
}
|
|
@@ -249,7 +250,7 @@ class MouseStepAction extends StepAction {
|
|
|
249
250
|
var done = arguments[1];
|
|
250
251
|
return dnd.call(null, eventData, done);
|
|
251
252
|
`;
|
|
252
|
-
return this.driver.executeCodeAsync(html5DNDCode, timeout, eventParam)
|
|
253
|
+
return this.driver.executeCodeAsync(html5DNDCode, timeout, eventParam);
|
|
253
254
|
}
|
|
254
255
|
|
|
255
256
|
const html5DNDCode = `
|
|
@@ -313,7 +314,7 @@ class MouseStepAction extends StepAction {
|
|
|
313
314
|
if (events.find(event => event.event === 'dragend')) {
|
|
314
315
|
return events;
|
|
315
316
|
}
|
|
316
|
-
|
|
317
|
+
const dragendDefaultEvent = {
|
|
317
318
|
event: 'dragend',
|
|
318
319
|
eventInfo: {
|
|
319
320
|
detail: 0,
|
|
@@ -365,8 +366,8 @@ class MouseStepAction extends StepAction {
|
|
|
365
366
|
}
|
|
366
367
|
|
|
367
368
|
generateHTML5DragEventSequence() {
|
|
368
|
-
|
|
369
|
-
|
|
369
|
+
const fromElement = this.context.data.targetId;
|
|
370
|
+
const toElement = this.context.data.toElement;
|
|
370
371
|
let events = this.step.events.filter(event => event.event !== 'mousemove' && event.event !== 'pointermove');
|
|
371
372
|
events = this.fixEventSequence(events);
|
|
372
373
|
events = this.addElementLocatedElementToDragEvents(events, fromElement.locatedElement, toElement.locatedElement);
|
|
@@ -1,10 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
2
|
|
|
3
3
|
const { commonConstants } = require('../../commons/getSessionPlayerRequire');
|
|
4
4
|
const Promise = require('bluebird');
|
|
5
5
|
|
|
6
6
|
class StepAction {
|
|
7
|
-
|
|
8
7
|
constructor(step, context, frameHandler, exportsGlobal = {}, stepActionUtils, locateElementPlayer, exportsTest = {}) {
|
|
9
8
|
this.step = step;
|
|
10
9
|
this.context = context;
|
|
@@ -21,21 +20,19 @@ class StepAction {
|
|
|
21
20
|
}
|
|
22
21
|
|
|
23
22
|
performAction() {
|
|
24
|
-
throw new Error(
|
|
23
|
+
throw new Error('not implemented');
|
|
25
24
|
}
|
|
26
25
|
|
|
27
26
|
getTarget() {
|
|
28
|
-
const targetId = this.step.targetId ||
|
|
27
|
+
const targetId = this.step.targetId || 'targetId';
|
|
29
28
|
return this.context.data[targetId];
|
|
30
29
|
}
|
|
31
30
|
|
|
32
31
|
execute(stepActionFactory, step) {
|
|
33
32
|
return Promise.resolve(this.performAction(stepActionFactory, step))
|
|
34
|
-
.then(res => {
|
|
35
|
-
return Promise.resolve(Object.assign({}, {success: true}, res));
|
|
36
|
-
})
|
|
33
|
+
.then(res => Promise.resolve(Object.assign({}, { success: true }, res)))
|
|
37
34
|
.catch(err => {
|
|
38
|
-
const errorMsg = (err || {}).message || err && err.seleniumStack && err.seleniumStack.message;
|
|
35
|
+
const errorMsg = (err || {}).message || (err && err.seleniumStack && err.seleniumStack.message);
|
|
39
36
|
const displayMsg = (err || {}).displayMessage;
|
|
40
37
|
return Promise.resolve({
|
|
41
38
|
success: false,
|
|
@@ -43,11 +40,11 @@ class StepAction {
|
|
|
43
40
|
exception: err,
|
|
44
41
|
errorType: commonConstants.stepResult.ACTION_EXCEPTION,
|
|
45
42
|
resultInfo: {
|
|
46
|
-
exception:
|
|
43
|
+
exception: `selenium exception: ${errorMsg}`,
|
|
47
44
|
// clickim -> playbackStepResultHandler.js -> FAILURE_REASON_MAPPING -> ACTION_EXCEPTION
|
|
48
45
|
// expects resultInfo.error or resultInfo.reason
|
|
49
46
|
error: displayMsg || errorMsg,
|
|
50
|
-
}
|
|
47
|
+
},
|
|
51
48
|
});
|
|
52
49
|
});
|
|
53
50
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
2
|
|
|
3
3
|
const LocateStepAction = require('./locateStepAction');
|
|
4
4
|
const ScrollStepAction = require('./scrollStepAction');
|
|
@@ -48,69 +48,69 @@ function register(stepActionByType, stepActionFactory) {
|
|
|
48
48
|
|
|
49
49
|
module.exports = function (driver, stepActionFactory, runMode) {
|
|
50
50
|
const STEP_ACTION_MAPPING = {
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
51
|
+
locate: LocateStepAction,
|
|
52
|
+
scroll: ScrollStepAction,
|
|
53
|
+
mouse: MouseStepAction,
|
|
54
|
+
submit: SubmitStepAction,
|
|
55
|
+
text: TextStepAction,
|
|
56
|
+
'special-key': SpecialKeyStepAction,
|
|
57
|
+
'user-code': JsCodeStepAction,
|
|
58
|
+
'validation-code-step': JsCodeStepAction,
|
|
59
|
+
'wait-for-code-step': JsCodeStepAction,
|
|
60
|
+
'action-code-step': JsCodeStepAction,
|
|
61
|
+
'condition-step': JsConditionStepAction,
|
|
62
|
+
'skip-code-step': JsConditionStepAction,
|
|
63
|
+
'element-code-step': JsConditionStepAction,
|
|
64
|
+
'evaluate-expression': EvaluateExpressionStepAction,
|
|
65
|
+
'text-validation': TextValidationStepAction,
|
|
66
|
+
'wait-for-text-validation': TextValidationStepAction,
|
|
67
|
+
'select-option': SelectOptionStepAction,
|
|
68
|
+
'drop-file': DropFileStepAction,
|
|
69
|
+
'input-file': InputFileStepAction,
|
|
70
|
+
hover: HoverStepAction,
|
|
71
|
+
navigation: NavigationStepAction,
|
|
72
|
+
wheel: WheelStepAction,
|
|
73
|
+
sleep: SleepStepAction,
|
|
74
|
+
refresh: RefreshStepAction,
|
|
75
|
+
'api-validation': ApiStepAction,
|
|
76
|
+
'api-action': ApiStepAction,
|
|
77
|
+
'api-code-step': JsCodeStepAction,
|
|
78
|
+
'extract-text': ExtractTextStepAction,
|
|
79
|
+
|
|
80
|
+
'cli-validation-download-file': ExtensionOnlyStepAction,
|
|
81
|
+
'cli-wait-for-download-file': ExtensionOnlyStepAction,
|
|
82
|
+
'network-validation-step': ExtensionOnlyStepAction,
|
|
83
|
+
|
|
84
|
+
'cli-validation-code-step': CliJsStepAction,
|
|
85
|
+
'cli-wait-for-code-step': CliJsStepAction,
|
|
86
|
+
'cli-action-code-step': CliJsStepAction,
|
|
87
|
+
'cli-api-code-step': CliJsStepAction,
|
|
88
|
+
|
|
89
|
+
'cli-condition-step': CliConditionStepAction,
|
|
90
|
+
'node-package': NodePackageStepAction,
|
|
91
|
+
|
|
92
|
+
'email-code-step': JsCodeStepAction,
|
|
93
|
+
'cli-email-code-step': CliJsStepAction,
|
|
94
|
+
'tdk-hybrid': TdkHybridStepAction,
|
|
95
95
|
};
|
|
96
96
|
|
|
97
97
|
const ANDROID_STEP_ACTION_MAPPING = {
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
98
|
+
locate: AndroidLocateStepAction,
|
|
99
|
+
'android-tap': MobileTapStepAction,
|
|
100
|
+
'android-long-click': AndroidLongClickStepAction,
|
|
101
101
|
'android-device-key': MobileGlobalActionStepAction,
|
|
102
102
|
'android-key-board-special-keys': AndroidSpecialKeyStepAction,
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
103
|
+
text: MobileTextChangeStepAction,
|
|
104
|
+
'android-swipe': AndroidSwipeStepAction,
|
|
105
|
+
'android-scroll': AndroidScrollStepAction,
|
|
106
106
|
};
|
|
107
107
|
|
|
108
108
|
const IOS_STEP_ACTION_MAPPING = {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
109
|
+
locate: IosLocateStepAction,
|
|
110
|
+
'ios-tap': MobileTapStepAction,
|
|
111
|
+
'ios-device-key': MobileGlobalActionStepAction,
|
|
112
|
+
text: MobileTextChangeStepAction,
|
|
113
|
+
'ios-scroll': IosScrollStepAction,
|
|
114
114
|
};
|
|
115
115
|
|
|
116
116
|
register(STEP_ACTION_MAPPING, stepActionFactory);
|
|
@@ -119,7 +119,7 @@ module.exports = function (driver, stepActionFactory, runMode) {
|
|
|
119
119
|
}
|
|
120
120
|
|
|
121
121
|
// override android actions
|
|
122
|
-
if (runMode ===
|
|
122
|
+
if (runMode === 'android') {
|
|
123
123
|
register(ANDROID_STEP_ACTION_MAPPING, stepActionFactory);
|
|
124
124
|
if (stepActionFactory.registerLocateStepActionUtils) {
|
|
125
125
|
stepActionFactory.registerLocateStepActionUtils(AndroidLocateStepAction.getUtils(driver));
|
|
@@ -127,7 +127,7 @@ module.exports = function (driver, stepActionFactory, runMode) {
|
|
|
127
127
|
}
|
|
128
128
|
|
|
129
129
|
// override ios actions
|
|
130
|
-
if (runMode ===
|
|
130
|
+
if (runMode === 'ios') {
|
|
131
131
|
register(IOS_STEP_ACTION_MAPPING, stepActionFactory);
|
|
132
132
|
if (stepActionFactory.registerLocateStepActionUtils) {
|
|
133
133
|
stepActionFactory.registerLocateStepActionUtils(IosLocateStepAction.getUtils(driver));
|
package/runOptions.js
CHANGED
|
@@ -348,6 +348,7 @@ program
|
|
|
348
348
|
.option('--aws-access-key-id [accessKeyId]', 'accessKeyId', '')
|
|
349
349
|
.option('--aws-secret-access-key [secretAccessKey]', 'secretAccessKey', '')
|
|
350
350
|
|
|
351
|
+
.option('--high-speed', 'run in high speed mode')
|
|
351
352
|
.option('--lightweight-mode [settings]', 'run lightweight mode')
|
|
352
353
|
.option('--create-prefeched-data [location]', 'prefech data into local cache file')
|
|
353
354
|
.option('--use-prefeched-data [location]', 'use prefeched data from local cache file, and force using only cached data')
|
|
@@ -1020,6 +1021,7 @@ module.exports = {
|
|
|
1020
1021
|
const DEFAULTS = {
|
|
1021
1022
|
general: true,
|
|
1022
1023
|
disableLabs: true,
|
|
1024
|
+
disableFeatureFlags: true,
|
|
1023
1025
|
disableAssets: true,
|
|
1024
1026
|
disablePixelValidation: true,
|
|
1025
1027
|
disableResults: true,
|
|
@@ -1029,10 +1031,13 @@ module.exports = {
|
|
|
1029
1031
|
disableVisibilityCheck: false,
|
|
1030
1032
|
disableLocators: false,
|
|
1031
1033
|
bypassSetup: false,
|
|
1034
|
+
disableAutoImprove: true,
|
|
1032
1035
|
disableQuotaBlocking: true,
|
|
1033
1036
|
onlyTestIdsNoSuite: true,
|
|
1034
1037
|
uploadAssetsAndResultsOnFailure: true,
|
|
1035
1038
|
preloadTests: true,
|
|
1039
|
+
disableProjectDefaults: true,
|
|
1040
|
+
type: 'lightweight',
|
|
1036
1041
|
};
|
|
1037
1042
|
|
|
1038
1043
|
const lightweightModeOptions = typeof program.lightweightMode === 'string' ? JSON.parse(program.lightweightMode) : {};
|
|
@@ -1040,8 +1045,33 @@ module.exports = {
|
|
|
1040
1045
|
} catch (err) {
|
|
1041
1046
|
return Promise.reject(new ArgError(`failed to parse lightweightMode settings error: ${err.message}`));
|
|
1042
1047
|
}
|
|
1048
|
+
} else if (program.highSpeed && program.mode === CLI_MODE.EXTENSION) {
|
|
1049
|
+
program.lightweightMode = {
|
|
1050
|
+
general: true,
|
|
1051
|
+
disableLabs: false,
|
|
1052
|
+
disableFeatureFlags: false,
|
|
1053
|
+
disableAssets: true,
|
|
1054
|
+
disablePixelValidation: false,
|
|
1055
|
+
disableResults: true,
|
|
1056
|
+
disableStepDelay: true,
|
|
1057
|
+
disableRemoteStep: false,
|
|
1058
|
+
assumePreloadedSharedSteps: false,
|
|
1059
|
+
disableVisibilityCheck: false,
|
|
1060
|
+
disableLocators: false,
|
|
1061
|
+
bypassSetup: false,
|
|
1062
|
+
disableQuotaBlocking: false,
|
|
1063
|
+
disableAutoImprove: false,
|
|
1064
|
+
onlyTestIdsNoSuite: false,
|
|
1065
|
+
uploadAssetsAndResultsOnFailure: true,
|
|
1066
|
+
preloadTests: false,
|
|
1067
|
+
disableProjectDefaults: false,
|
|
1068
|
+
type: 'highSpeed',
|
|
1069
|
+
};
|
|
1043
1070
|
}
|
|
1044
1071
|
|
|
1072
|
+
if (typeof program.baseUrl === 'boolean') {
|
|
1073
|
+
return Promise.reject(new ArgError('base url cannot be used as a flag, and must contain a string value'));
|
|
1074
|
+
}
|
|
1045
1075
|
|
|
1046
1076
|
return ({
|
|
1047
1077
|
testId: [].concat(program.testId),
|
package/runner.js
CHANGED
|
@@ -308,6 +308,11 @@ async function init(options) {
|
|
|
308
308
|
if (!(options.lightweightMode && options.lightweightMode.disableLabs)) {
|
|
309
309
|
await labFeaturesService.loadLabFeatures(projectById.id, companyByProjectId.activePlan);
|
|
310
310
|
}
|
|
311
|
+
|
|
312
|
+
if (options.lightweightMode && options.lightweightMode.type === 'highSpeed' && !labFeaturesService.isFeatureAvailableForProject('highSpeedMode')) {
|
|
313
|
+
delete options.lightweightMode;
|
|
314
|
+
}
|
|
315
|
+
|
|
311
316
|
gridService.keepAlive.start(project);
|
|
312
317
|
analyticsIdentify(project);
|
|
313
318
|
await setMockNetworkRules(options);
|
|
@@ -23,11 +23,18 @@ const calcSource = (source, user) => {
|
|
|
23
23
|
return source;
|
|
24
24
|
};
|
|
25
25
|
|
|
26
|
+
function setLightweightAnalytics(properties, lightweightMode) {
|
|
27
|
+
if (lightweightMode && lightweightMode.type) {
|
|
28
|
+
properties[`${lightweightMode.type}Mode`] = true;
|
|
29
|
+
}
|
|
30
|
+
return properties;
|
|
31
|
+
}
|
|
32
|
+
|
|
26
33
|
class BaseStrategy {
|
|
27
34
|
analyticsTestStart({
|
|
28
35
|
executionId, projectId, testId, resultId, companyId, companyName, projectName, companyPlanType, sessionType, source, user, lightweightMode,
|
|
29
36
|
}) {
|
|
30
|
-
|
|
37
|
+
const properties = setLightweightAnalytics({
|
|
31
38
|
executionId,
|
|
32
39
|
projectId,
|
|
33
40
|
testId,
|
|
@@ -37,15 +44,15 @@ class BaseStrategy {
|
|
|
37
44
|
projectName,
|
|
38
45
|
companyPlanType,
|
|
39
46
|
sessionType,
|
|
40
|
-
lightweightMode,
|
|
41
47
|
source: calcSource(source, user),
|
|
42
|
-
});
|
|
48
|
+
}, lightweightMode);
|
|
49
|
+
analytics.trackWithCIUser('test-run-ci', properties);
|
|
43
50
|
}
|
|
44
51
|
|
|
45
52
|
analyticsTestEnd({
|
|
46
53
|
executionId, projectId, testId, resultId, result, companyId, companyName, projectName, companyPlanType, sessionType, source, user, lightweightMode,
|
|
47
54
|
}) {
|
|
48
|
-
const properties = {
|
|
55
|
+
const properties = setLightweightAnalytics({
|
|
49
56
|
executionId,
|
|
50
57
|
projectId,
|
|
51
58
|
testId,
|
|
@@ -56,9 +63,8 @@ class BaseStrategy {
|
|
|
56
63
|
companyPlanType,
|
|
57
64
|
sessionType,
|
|
58
65
|
mockNetworkEnabled: result.wasMockNetworkActivated,
|
|
59
|
-
lightweightMode,
|
|
60
66
|
source: calcSource(source, user),
|
|
61
|
-
};
|
|
67
|
+
}, lightweightMode);
|
|
62
68
|
|
|
63
69
|
if (result.success) {
|
|
64
70
|
analytics.trackWithCIUser('test-run-ci-success', properties);
|
|
@@ -74,7 +74,7 @@ class LocalStrategy extends BaseStrategy {
|
|
|
74
74
|
const user = options.user;
|
|
75
75
|
const companyPlanType = options.company && options.company.planType;
|
|
76
76
|
const projectName = options.projectData && options.projectData.name;
|
|
77
|
-
const lightweightMode =
|
|
77
|
+
const lightweightMode = options.lightweightMode;
|
|
78
78
|
const sessionType = utils.getSessionType(options);
|
|
79
79
|
|
|
80
80
|
const onTestStarted = (wid, testId, resultId, isRerun, testRetryKey) => {
|
|
@@ -96,11 +96,12 @@ class LocalStrategy extends BaseStrategy {
|
|
|
96
96
|
return testStatus.testStartAndReport(wid, executionId, resultId, isRerun, testRetryKey);
|
|
97
97
|
};
|
|
98
98
|
const onTestCompleted = (wid, testId, testResult, sessionId, isRerun) => testStatus.testEndAndReport(wid, testResult, executionId, sessionId, isRerun).then(() => {
|
|
99
|
-
|
|
99
|
+
const isLocalRun = Boolean(options.useLocalChromeDriver || options.useChromeLauncher);
|
|
100
|
+
if (lightweightMode && lightweightMode.disableResults && isLocalRun) {
|
|
100
101
|
return undefined;
|
|
101
102
|
}
|
|
102
103
|
const update = {};
|
|
103
|
-
if (
|
|
104
|
+
if (lightweightMode && lightweightMode.onlyTestIdsNoSuite) {
|
|
104
105
|
update.show = true;
|
|
105
106
|
}
|
|
106
107
|
if (testResult.seleniumStats) {
|
package/testRunHandler.js
CHANGED
|
@@ -518,7 +518,7 @@ TestRun.prototype.onRetry = async function () {
|
|
|
518
518
|
this._originalTestResultId = this._originalTestResultId || this._previousTestResultId;
|
|
519
519
|
this._testResultId = utils.guid();
|
|
520
520
|
|
|
521
|
-
if (this._options.lightweightMode && this._options.lightweightMode.
|
|
521
|
+
if (this._options.lightweightMode && this._options.lightweightMode.onlyTestIdsNoSuite) {
|
|
522
522
|
return;
|
|
523
523
|
}
|
|
524
524
|
|
package/testRunStatus.js
CHANGED
|
@@ -47,6 +47,7 @@ const RunStatus = function (testInfoList, options, testPlanId, branchToUse) {
|
|
|
47
47
|
this.executionStartedPromise = Promise.resolve();
|
|
48
48
|
|
|
49
49
|
const browserNames = utils.getUniqBrowsers(options, testInfoList);
|
|
50
|
+
const runnerMode = options.lightweightMode ? options.lightweightMode.type : options.mode;
|
|
50
51
|
this.execConfig = {
|
|
51
52
|
parallel: TESTIM_CONCURRENT_WORKER_COUNT || options.parallel || 1,
|
|
52
53
|
browser: browserNames,
|
|
@@ -74,7 +75,7 @@ const RunStatus = function (testInfoList, options, testPlanId, branchToUse) {
|
|
|
74
75
|
tunnel: options.tunnel,
|
|
75
76
|
tunnelPort: options.tunnelPort,
|
|
76
77
|
tunnelHostHeader: options.tunnelHostHeader,
|
|
77
|
-
runnerMode
|
|
78
|
+
runnerMode,
|
|
78
79
|
gridId: options.gridId || options.gridData.gridId,
|
|
79
80
|
gridName: options.grid || options.gridData.name,
|
|
80
81
|
gridType: options.gridData.type,
|
|
@@ -152,7 +153,7 @@ RunStatus.prototype.testStart = function (wid, executionId, resultId, isRerun) {
|
|
|
152
153
|
|
|
153
154
|
RunStatus.prototype.updateTestStatusRunning = function (test, executionId, testRetryKey) {
|
|
154
155
|
const { project: projectId, remoteRunId, projectData } = this.options;
|
|
155
|
-
if (this.options.lightweightMode && this.options.lightweightMode.
|
|
156
|
+
if (this.options.lightweightMode && this.options.lightweightMode.onlyTestIdsNoSuite) {
|
|
156
157
|
return this.executionStartedPromise;
|
|
157
158
|
}
|
|
158
159
|
|
|
@@ -184,9 +185,6 @@ RunStatus.prototype.testStartReport = function (test, executionId, testRetryKey)
|
|
|
184
185
|
.then(params => {
|
|
185
186
|
this.options.runParams[test.resultId] = test.config.testData = Object.assign({}, test.config.testData, this.exportsGlobal, this.fileUserParamsData, this.beforeSuiteParams, params);
|
|
186
187
|
test.startTime = Date.now();
|
|
187
|
-
if (this.options.lightweightMode && this.options.lightweightMode.disableResults) {
|
|
188
|
-
return undefined;
|
|
189
|
-
}
|
|
190
188
|
return this.updateTestStatusRunning(test, executionId, testRetryKey);
|
|
191
189
|
}).catch(err => {
|
|
192
190
|
logger.error('Failed to start test', { err });
|
|
@@ -283,7 +281,7 @@ RunStatus.prototype.testEndReport = function (test, executionId, result) {
|
|
|
283
281
|
const globalParameters = result.exportsGlobal;
|
|
284
282
|
return runHook(this.options.afterTest, Object.assign({}, test, { globalParameters }))
|
|
285
283
|
.then(() => {
|
|
286
|
-
if (this.options.lightweightMode && this.options.lightweightMode.
|
|
284
|
+
if (this.options.lightweightMode && this.options.lightweightMode.onlyTestIdsNoSuite) {
|
|
287
285
|
return undefined;
|
|
288
286
|
}
|
|
289
287
|
return servicesApi.updateTestStatus('FINISHED', executionId, test.testId, test.resultId, test.startTime, result.endTime, test.success, test.failureReason, null, this.options.project, this.options.remoteRunId);
|
|
@@ -446,7 +444,7 @@ RunStatus.prototype.executionEnd = function (executionId) {
|
|
|
446
444
|
.then((coverageSummary) => {
|
|
447
445
|
resultExtraData.coverageSummary = coverageSummary;
|
|
448
446
|
|
|
449
|
-
if (this.options.lightweightMode && this.options.lightweightMode.
|
|
447
|
+
if (this.options.lightweightMode && this.options.lightweightMode.onlyTestIdsNoSuite) {
|
|
450
448
|
return undefined;
|
|
451
449
|
}
|
|
452
450
|
return servicesApi.reportExecutionFinished(
|