@testim/testim-cli 3.252.0 → 3.254.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/OverrideTestDataBuilder.js +1 -1
- package/agent/routers/cliJsCode/index.js +4 -4
- package/agent/routers/cliJsCode/router.js +46 -42
- package/agent/routers/cliJsCode/service.js +18 -13
- package/agent/routers/codim/router.js +14 -17
- package/agent/routers/codim/router.test.js +15 -14
- package/agent/routers/codim/service.js +1 -1
- package/agent/routers/general/index.js +4 -8
- package/agent/routers/hybrid/registerRoutes.js +18 -18
- package/agent/routers/index.js +9 -8
- package/agent/routers/playground/router.js +12 -11
- package/agent/routers/playground/service.js +19 -18
- package/agent/routers/standalone-browser/registerRoutes.js +10 -10
- package/cdpTestRunner.js +4 -3
- package/chromiumInstaller.js +4 -5
- package/cli/onExit.js +2 -2
- package/cli.js +7 -6
- package/cliAgentMode.js +4 -5
- package/codim/codim-cli.js +11 -10
- package/codim/hybrid-utils.js +1 -1
- package/codim/measure-perf.js +9 -6
- package/codim/template.js/tests/examples/01-simple-text-validation.test.js +6 -6
- package/codim/template.js/tests/examples/02-using-locators.test.js +13 -15
- package/codim/template.js/tests/examples/03-using-hooks.test.js +17 -19
- package/codim/template.js/tests/examples/04-skip-and-only.test.js +16 -17
- package/codim/template.js/tests/examples/05-multiple-windows.test.js +16 -17
- package/codim/template.js/webpack.config.js +1 -1
- package/codim/template.ts/webpack.config.js +3 -3
- package/commons/AbortError.js +4 -4
- package/commons/chrome-launcher.js +6 -6
- package/commons/constants.js +2 -0
- package/commons/detectDebugger.js +4 -2
- package/commons/getSessionPlayerRequire.js +2 -20
- package/commons/initializeUserWithAuth.js +2 -2
- package/commons/lazyRequire.js +10 -9
- package/commons/logger.js +4 -4
- package/commons/performance-logger.js +14 -8
- package/commons/prepareRunnerAndTestimStartUtils.js +6 -7
- package/commons/socket/baseSocketServiceSocketIO.js +32 -34
- package/commons/socket/realDataService.js +6 -5
- package/commons/socket/realDataServiceSocketIO.js +4 -4
- package/commons/socket/remoteStepService.js +4 -3
- package/commons/socket/remoteStepServiceSocketIO.js +11 -12
- package/commons/socket/socketService.js +50 -52
- package/commons/socket/testResultServiceSocketIO.js +11 -11
- package/commons/testimDesiredCapabilitiesBuilder.js +44 -0
- package/commons/testimNgrok.js +2 -2
- package/commons/testimNgrok.test.js +1 -1
- package/commons/testimServicesApi.js +37 -21
- package/commons/xhr2.js +97 -100
- package/credentialsManager.js +17 -20
- package/errors.js +5 -0
- package/fixLocalBuild.js +2 -0
- package/npm-shrinkwrap.json +4455 -1576
- package/package.json +9 -7
- package/player/WebdriverioWebDriverApi.js +7 -2
- package/player/appiumTestPlayer.js +102 -0
- package/player/chromeLauncherTestPlayer.js +0 -1
- 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/services/tabServiceMock.js +166 -0
- package/player/stepActions/navigationStepAction.js +11 -10
- package/player/stepActions/sleepStepAction.js +4 -5
- package/player/stepActions/stepAction.js +15 -1
- package/player/stepActions/textStepAction.js +4 -11
- package/player/utils/stepActionUtils.js +4 -2
- package/player/utils/windowUtils.js +139 -125
- package/player/webdriver.js +40 -26
- package/processHandler.js +3 -3
- package/processHandler.test.js +1 -1
- package/reports/consoleReporter.js +3 -2
- package/reports/debugReporter.js +41 -39
- package/reports/jsonReporter.js +53 -50
- package/reports/junitReporter.js +1 -2
- package/reports/reporter.js +135 -136
- package/runOptions.js +8 -7
- package/runner.js +13 -0
- package/runners/ParallelWorkerManager.js +2 -0
- package/runners/TestPlanRunner.js +142 -74
- package/runners/buildCodeTests.js +38 -37
- package/runners/runnerUtils.js +3 -3
- package/services/lambdatestService.js +3 -5
- package/stepPlayers/cliJsStepPlayback.js +22 -17
- package/testRunHandler.js +8 -0
- package/testRunStatus.js +458 -460
- package/{utils.js → utils/index.js} +25 -117
- package/utils/promiseUtils.js +78 -0
- package/utils/stringUtils.js +96 -0
- package/{utils.test.js → utils/utils.test.js} +2 -2
- package/workers/BaseWorker.js +29 -20
- package/workers/WorkerAppium.js +123 -0
- package/workers/WorkerExtensionSingleBrowser.js +4 -4
- package/workers/WorkerSelenium.js +5 -2
|
@@ -1,15 +1,15 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
2
|
|
|
3
|
-
const { exec } = require(
|
|
3
|
+
const { exec } = require('child_process');
|
|
4
4
|
|
|
5
|
-
module.exports.launchChrome = function(url) {
|
|
5
|
+
module.exports.launchChrome = function (url) {
|
|
6
6
|
const { platform } = process;
|
|
7
7
|
|
|
8
|
-
if (platform ===
|
|
8
|
+
if (platform === 'win32') {
|
|
9
9
|
exec(`start chrome ${url}`);
|
|
10
|
-
} else if (platform ===
|
|
10
|
+
} else if (platform === 'darwin') {
|
|
11
11
|
exec(`open -a "Google Chrome" ${url}`);
|
|
12
|
-
} else if (platform ===
|
|
12
|
+
} else if (platform === 'linux') {
|
|
13
13
|
exec(`google-chrome ${url}`);
|
|
14
14
|
}
|
|
15
15
|
};
|
package/commons/constants.js
CHANGED
|
@@ -41,6 +41,7 @@ module.exports = {
|
|
|
41
41
|
CLI_MODE: {
|
|
42
42
|
EXTENSION: 'extension',
|
|
43
43
|
SELENIUM: 'selenium',
|
|
44
|
+
APPIUM: 'appium',
|
|
44
45
|
},
|
|
45
46
|
sessionType: {
|
|
46
47
|
CODELESS: 'codeless',
|
|
@@ -54,6 +55,7 @@ module.exports = {
|
|
|
54
55
|
HYBRID: 'testimHybrid',
|
|
55
56
|
BROWSERSTACK: 'browserstack',
|
|
56
57
|
SAUCELABS: 'saucelabs',
|
|
58
|
+
TESTIM_HEADSPIN: 'testimHeadspin',
|
|
57
59
|
},
|
|
58
60
|
stepResult: {
|
|
59
61
|
SETUP_TIMEOUT: 'setup-timeout',
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
2
3
|
const { DISABLE_DEBUGGER_INFINITE_TIMEOUT } = require('./config');
|
|
3
4
|
|
|
4
5
|
module.exports.isDebuggerConnected = () => {
|
|
@@ -12,6 +13,7 @@ module.exports.isDebuggerConnected = () => {
|
|
|
12
13
|
return true;
|
|
13
14
|
}
|
|
14
15
|
} catch (e) {
|
|
15
|
-
|
|
16
|
+
/* empty */
|
|
16
17
|
}
|
|
18
|
+
return false;
|
|
17
19
|
};
|
|
@@ -3,28 +3,10 @@
|
|
|
3
3
|
const perf = require('./performance-logger');
|
|
4
4
|
|
|
5
5
|
perf.log('getSessionPlayerRequire start');
|
|
6
|
-
const getSessionPlayerFolder = require('./prepareRunnerAndTestimStartUtils')
|
|
6
|
+
const { getSessionPlayerFolder } = require('./prepareRunnerAndTestimStartUtils');
|
|
7
7
|
|
|
8
8
|
const testimAppDataFolder = getSessionPlayerFolder();
|
|
9
|
-
/**
|
|
10
|
-
* @type {{
|
|
11
|
-
sessionPlayer: typeof import('../../../clickim/src/background/session/sessionPlayer').SessionPlayer;
|
|
12
|
-
utils: typeof import('../../../clickim/src/lib/utils').utils;
|
|
13
|
-
commonConstants: typeof import('../../../clickim/src/common/commonConstantsStrong');
|
|
14
|
-
locatorBuilderUtils: import('../../../clickim/src/locators/locatorBuilderUtils')['locatorBuilderUtils'];
|
|
15
|
-
assetService: import('../../../clickim/src/background/assetService')['assetService'];
|
|
16
|
-
localAssetService: import('../../../clickim/src/background/localAssetService');
|
|
17
|
-
urlUtils: import('../../../clickim/src/background/portMatch/urlUtils');
|
|
18
|
-
positionUtils: import('../../../clickim/src/lib/positionUtils');
|
|
19
|
-
visibilityUtils: import('../../../clickim/src/background/visibilityUtils');
|
|
20
|
-
apiCall: import('../../../clickim/src/common/playback/apiCall')['apiCall'];
|
|
21
|
-
stepParamBuilder: typeof import('../../../clickim/src/common/stepParamsBuilder').StepParamsBuilder;
|
|
22
|
-
stepParamExpressionEvaluator: import('../../../clickim/src/common/stepParamExpressionEvaluator');
|
|
23
|
-
manifestVersion: string | undefined;
|
|
24
|
-
EyeSdkBuilder: typeof import('../../../clickim/src/background/eyeSdkBuilder').EyeSdkBuilder;
|
|
25
|
-
sfdc: typeof import('sfdc-engine');
|
|
26
|
-
}}
|
|
27
|
-
*/
|
|
9
|
+
/** @type {import('clickim/src/background/sessionPlayerInit').SessionPlayerInit} */
|
|
28
10
|
const sessionPlayer = require(require('path').join(testimAppDataFolder, 'sessionPlayer.js')); // eslint-disable-line import/no-dynamic-require
|
|
29
11
|
|
|
30
12
|
module.exports = sessionPlayer;
|
|
@@ -3,7 +3,7 @@ const perf = require('./performance-logger');
|
|
|
3
3
|
const localRunnerCache = require('./runnerFileCache');
|
|
4
4
|
const servicesApi = require('./testimServicesApi.js');
|
|
5
5
|
const testimCustomToken = require('./testimCustomToken');
|
|
6
|
-
|
|
6
|
+
const { CLI_MODE } = require('./constants');
|
|
7
7
|
|
|
8
8
|
const FIVE_MINUTES_MS = 1000 * 60 * 5;
|
|
9
9
|
const TEN_HOURS_MS = 1000 * 60 * 60 * 10;
|
|
@@ -11,7 +11,7 @@ const TEN_HOURS_MS = 1000 * 60 * 60 * 10;
|
|
|
11
11
|
function preloadSlowRequires(mode) {
|
|
12
12
|
process.nextTick(() => {
|
|
13
13
|
// heuristic to pay the cost of loading the sessionPlayer here while we are waiting for the backend
|
|
14
|
-
if (mode ===
|
|
14
|
+
if (mode === CLI_MODE.SELENIUM || mode === CLI_MODE.APPIUM) {
|
|
15
15
|
try {
|
|
16
16
|
require('./getSessionPlayerRequire');
|
|
17
17
|
// jsdom for the same reason, we don't require workerSelenium here since it actually takes longer to load
|
package/commons/lazyRequire.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
2
|
|
|
3
3
|
const Bluebird = require('bluebird');
|
|
4
4
|
const npmWrapper = require('./npmWrapper');
|
|
5
5
|
const ora = require('ora');
|
|
6
6
|
const path = require('path');
|
|
7
|
-
const logger = require('./logger').getLogger(
|
|
7
|
+
const logger = require('./logger').getLogger('lazy-require');
|
|
8
8
|
const { getCliLocation } = require('../utils');
|
|
9
|
-
const { requireWithFallback } = require(
|
|
9
|
+
const { requireWithFallback } = require('./requireWithFallback');
|
|
10
10
|
|
|
11
|
+
// eslint-disable-next-line import/no-dynamic-require
|
|
11
12
|
const packageJson = require(path.resolve(getCliLocation(), 'package.json'));
|
|
12
13
|
const ongoingCalls = new Map();
|
|
13
14
|
|
|
@@ -29,14 +30,14 @@ module.exports = async function memoizedLazyRequireApi(dependency, options = {})
|
|
|
29
30
|
}
|
|
30
31
|
return requiredModule;
|
|
31
32
|
} catch (error) {
|
|
32
|
-
logger.warn(
|
|
33
|
+
logger.warn('failed to install dependency lazily', { dependency, err: error });
|
|
33
34
|
const depVersionToInstall = getVersionOfLazyDep(dependency);
|
|
34
35
|
const depWithVersions = `${dependency}@${depVersionToInstall}`;
|
|
35
36
|
|
|
36
37
|
const removeGlobal = process.argv.includes('npx');
|
|
37
|
-
const globalFlag = removeGlobal ? '' : '-g '
|
|
38
|
+
const globalFlag = removeGlobal ? '' : '-g ';
|
|
38
39
|
const errorMessage = `Installation of ${dependency} failed. This typically means you are running an out-of-date version of Node.js or NPM.` +
|
|
39
|
-
`Please manually install by running the following command: npm install ${globalFlag}${depWithVersions}
|
|
40
|
+
`Please manually install by running the following command: npm install ${globalFlag}${depWithVersions}`;
|
|
40
41
|
|
|
41
42
|
if (spinner) {
|
|
42
43
|
spinner.fail(errorMessage);
|
|
@@ -52,12 +53,12 @@ async function memoizedLazyRequire(identifier, options = {}) {
|
|
|
52
53
|
}
|
|
53
54
|
|
|
54
55
|
ongoingCalls.set(identifier, lazyRequireImpl(identifier, options));
|
|
55
|
-
ongoingCalls.get(identifier).catch(
|
|
56
|
+
ongoingCalls.get(identifier).catch(() => {
|
|
56
57
|
ongoingCalls.delete(identifier);
|
|
57
58
|
});
|
|
58
59
|
|
|
59
60
|
return ongoingCalls.get(identifier);
|
|
60
|
-
}
|
|
61
|
+
}
|
|
61
62
|
|
|
62
63
|
async function lazyRequireImpl(dependency) {
|
|
63
64
|
const packageLocally = npmWrapper.getPackageIfInstalledLocally(dependency);
|
|
@@ -94,7 +95,7 @@ function getVersionOfLazyDep(dependencyToFind) {
|
|
|
94
95
|
.find(([dep]) => dep === dependencyToFind);
|
|
95
96
|
|
|
96
97
|
if (!depEntry) {
|
|
97
|
-
throw new Error(
|
|
98
|
+
throw new Error('The given package name is not lazyDependencies');
|
|
98
99
|
}
|
|
99
100
|
|
|
100
101
|
return depEntry[1];
|
package/commons/logger.js
CHANGED
|
@@ -53,7 +53,7 @@ function getStreamsAndWaitForFlushPromise() {
|
|
|
53
53
|
const [transports, waitForFlush] = getStreamsAndWaitForFlushPromise();
|
|
54
54
|
const level = config.LOGGER_DEBUG ? 'debug' : 'info';
|
|
55
55
|
const defaultMeta = {};
|
|
56
|
-
if (isLocal.
|
|
56
|
+
if (!isLocal.includes('@echo')) {
|
|
57
57
|
Object.assign(defaultMeta, devFlags());
|
|
58
58
|
|
|
59
59
|
} else {
|
|
@@ -149,13 +149,13 @@ class Logger {
|
|
|
149
149
|
this.innerLog('crit', msg, data);
|
|
150
150
|
}
|
|
151
151
|
|
|
152
|
-
innerLog(
|
|
152
|
+
innerLog(logLevel, msg, data = {}) {
|
|
153
153
|
try {
|
|
154
|
-
this._logger.log(
|
|
154
|
+
this._logger.log(logLevel, Object.assign({ meta: data }, { message: msg }, addExecutionMetadata(data.executionId)));
|
|
155
155
|
} catch (err) {
|
|
156
156
|
try {
|
|
157
157
|
this._logger.log('crit', Object.assign({ message: `failed to log message ${err.message}, ${err.stack}` }, addExecutionMetadata(data.executionId)));
|
|
158
|
-
} catch (
|
|
158
|
+
} catch (_err) {
|
|
159
159
|
// well what can we do
|
|
160
160
|
}
|
|
161
161
|
}
|
|
@@ -1,7 +1,9 @@
|
|
|
1
|
-
|
|
1
|
+
/* eslint-disable no-console */
|
|
2
|
+
|
|
3
|
+
'use strict';
|
|
2
4
|
|
|
3
5
|
const MEASURE_TESTIM_CLI_PERFORMANCE = process.env.MEASURE_TESTIM_CLI_PERFORMANCE;
|
|
4
|
-
|
|
6
|
+
const epoch = Date.now();
|
|
5
7
|
let last = Date.now();
|
|
6
8
|
|
|
7
9
|
module.exports = {
|
|
@@ -9,7 +11,7 @@ module.exports = {
|
|
|
9
11
|
if (!MEASURE_TESTIM_CLI_PERFORMANCE) {
|
|
10
12
|
return;
|
|
11
13
|
}
|
|
12
|
-
|
|
14
|
+
const time = Date.now();
|
|
13
15
|
console.log(`${time - epoch}\t\t\t${time - last}\t\t\t`, ...args);
|
|
14
16
|
last = time;
|
|
15
17
|
},
|
|
@@ -25,7 +27,9 @@ module.exports = {
|
|
|
25
27
|
}
|
|
26
28
|
},
|
|
27
29
|
patchPromisePrototype() {
|
|
28
|
-
|
|
30
|
+
// TODO: Stop monkey patching shit
|
|
31
|
+
// eslint-disable-next-line no-extend-native
|
|
32
|
+
Promise.prototype.log = function log(message) {
|
|
29
33
|
if (!MEASURE_TESTIM_CLI_PERFORMANCE) {
|
|
30
34
|
return this;
|
|
31
35
|
}
|
|
@@ -40,7 +44,7 @@ module.exports = {
|
|
|
40
44
|
return this;
|
|
41
45
|
}
|
|
42
46
|
return this.tap(() => module.exports.log(message));
|
|
43
|
-
}
|
|
47
|
+
};
|
|
44
48
|
},
|
|
45
49
|
measureRequireTimes() {
|
|
46
50
|
if (!MEASURE_TESTIM_CLI_PERFORMANCE) {
|
|
@@ -48,12 +52,14 @@ module.exports = {
|
|
|
48
52
|
}
|
|
49
53
|
const {
|
|
50
54
|
performance,
|
|
51
|
-
PerformanceObserver
|
|
55
|
+
PerformanceObserver,
|
|
52
56
|
} = require('perf_hooks');
|
|
53
57
|
const mod = require('module');
|
|
54
58
|
|
|
55
59
|
// Monkey patch the require function
|
|
56
60
|
mod.Module.prototype.require = performance.timerify(mod.Module.prototype.require);
|
|
61
|
+
// TODO: Stop monkey patching shit
|
|
62
|
+
// eslint-disable-next-line no-global-assign
|
|
57
63
|
require = performance.timerify(require);
|
|
58
64
|
|
|
59
65
|
// Activate the observer
|
|
@@ -65,8 +71,8 @@ module.exports = {
|
|
|
65
71
|
obs.disconnect();
|
|
66
72
|
});
|
|
67
73
|
obs.observe({ entryTypes: ['function'], buffered: true });
|
|
68
|
-
}
|
|
69
|
-
}
|
|
74
|
+
},
|
|
75
|
+
};
|
|
70
76
|
|
|
71
77
|
// ew ~ Benji
|
|
72
78
|
module.exports.patchPromisePrototype();
|
|
@@ -3,7 +3,6 @@
|
|
|
3
3
|
// @ts-ignore
|
|
4
4
|
const Promise = require('bluebird');
|
|
5
5
|
const path = require('path');
|
|
6
|
-
const os = require('os');
|
|
7
6
|
const fs = Promise.promisifyAll(require('fs'));
|
|
8
7
|
const ms = require('ms');
|
|
9
8
|
const { serializeError } = require('serialize-error');
|
|
@@ -42,11 +41,11 @@ function prepareCustomExtension(location, unlimitedSize = false) {
|
|
|
42
41
|
return getRemoteFileSizeInMB(location)
|
|
43
42
|
.then(contentLength => {
|
|
44
43
|
if (contentLength > MAX_CUSTOM_EXT_SIZE_MB && !unlimitedSize) {
|
|
45
|
-
|
|
44
|
+
throw new ArgError(MAX_CUSTOM_SIZE_ERROR_MSG);
|
|
46
45
|
}
|
|
47
46
|
return downloadAndSave(location, destFile);
|
|
48
47
|
})
|
|
49
|
-
.then(() =>
|
|
48
|
+
.then(() => destFile);
|
|
50
49
|
}
|
|
51
50
|
|
|
52
51
|
const destFile = path.resolve(location);
|
|
@@ -70,11 +69,11 @@ function getRemoteFileSizeInMB(url) {
|
|
|
70
69
|
.then(res => {
|
|
71
70
|
const contentLengthHeader = res.headers['content-length'];
|
|
72
71
|
const contentLengthBytes = contentLengthHeader ? parseInt(contentLengthHeader, 10) : 0;
|
|
73
|
-
return
|
|
72
|
+
return contentLengthBytes / 1000000;
|
|
74
73
|
})
|
|
75
74
|
.catch(err => {
|
|
76
75
|
logger.warn('failed to download custom extension', { err });
|
|
77
|
-
|
|
76
|
+
throw new ArgError(`Failed to download custom extension from location: ${url}`);
|
|
78
77
|
});
|
|
79
78
|
}
|
|
80
79
|
|
|
@@ -135,7 +134,7 @@ async function prepareChromeDriver(userDetails = {}, driverOptions = {}, skipIsR
|
|
|
135
134
|
function getPlayerVersion() {
|
|
136
135
|
const url = `${config.BLOB_URL}/extension/sessionPlayer_LATEST_RELEASE`;
|
|
137
136
|
return download(url)
|
|
138
|
-
.then(res =>
|
|
137
|
+
.then(res => res.body.toString('utf8'));
|
|
139
138
|
}
|
|
140
139
|
|
|
141
140
|
/**
|
|
@@ -150,7 +149,7 @@ function getPlayerLocation(location, canary) {
|
|
|
150
149
|
}
|
|
151
150
|
|
|
152
151
|
return getPlayerVersion()
|
|
153
|
-
.then(ver =>
|
|
152
|
+
.then(ver => `${location}-${ver}`);
|
|
154
153
|
}
|
|
155
154
|
|
|
156
155
|
function getSessionPlayerFolder() {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
2
|
|
|
3
3
|
const Promise = require('bluebird');
|
|
4
4
|
const pRetry = require('p-retry');
|
|
@@ -10,22 +10,21 @@ const MAX_RECONNECT_ATTEMPT_BEFORE_SWITCH = 10;
|
|
|
10
10
|
const EMIT_PROMISE_TIMEOUT = 5000;
|
|
11
11
|
const POLLING_TRANSPORT_TIMEOUT_MS = 10 * 1000;
|
|
12
12
|
|
|
13
|
-
const logger = require('../logger').getLogger(
|
|
13
|
+
const logger = require('../logger').getLogger('base socket service');
|
|
14
14
|
|
|
15
15
|
class BaseSocketServiceSocketIO {
|
|
16
|
-
|
|
17
16
|
constructor() {
|
|
18
17
|
this.attempts = 0;
|
|
19
18
|
this.rooms = {};
|
|
20
|
-
this.
|
|
19
|
+
this.emitPromiseQueue = undefined;
|
|
21
20
|
}
|
|
22
21
|
|
|
23
22
|
joinToMultipleResults() {
|
|
24
23
|
const testResultIds = Object.keys(this.rooms);
|
|
25
|
-
logger.info(
|
|
26
|
-
testResultIds.
|
|
24
|
+
logger.info('re-join all existing rooms', { testResultIds });
|
|
25
|
+
testResultIds.forEach(resultId => {
|
|
27
26
|
const testId = this.rooms[resultId];
|
|
28
|
-
this.emitJoinRoom
|
|
27
|
+
this.emitJoinRoom?.(resultId, testId);
|
|
29
28
|
});
|
|
30
29
|
}
|
|
31
30
|
|
|
@@ -43,20 +42,22 @@ class BaseSocketServiceSocketIO {
|
|
|
43
42
|
try {
|
|
44
43
|
transport = this._socket.io.engine.transport.name;
|
|
45
44
|
} catch (e) {
|
|
45
|
+
/* empty */
|
|
46
46
|
}
|
|
47
|
-
logger.error(`Error in SocketService websocket _${method}_ socket ${this._socket.id}
|
|
47
|
+
logger.error(`Error in SocketService websocket _${method}_ socket ${this._socket.id} ` +
|
|
48
|
+
`is ${this.url} over ${transport}. Reconnect attempts ${this.attempts}. Error is: ${err?.message}`);
|
|
48
49
|
};
|
|
49
50
|
|
|
50
51
|
this._socket.on('reconnect_attempt', (attempt) => {
|
|
51
|
-
socketError('reconnect_attempt', {message: 'reconnect attempt', attempt});
|
|
52
|
+
socketError('reconnect_attempt', { message: 'reconnect attempt', attempt });
|
|
52
53
|
this.attempts++;
|
|
53
54
|
if (this.attempts === MAX_RECONNECT_ATTEMPT_BEFORE_SWITCH && !this.isAllowedWS) {
|
|
54
55
|
this._socket.io.opts.transports = ['polling'];
|
|
55
56
|
this._socket.io.opts.upgrade = false;
|
|
56
57
|
}
|
|
57
58
|
if (this.attempts >= MAX_SOCKET_RECONNECT_ATTEMPT) {
|
|
58
|
-
throw new Error(
|
|
59
|
-
|
|
59
|
+
throw new Error('Can\'t connect to Testim Servers.\n' +
|
|
60
|
+
`Action required: Please allow opening a websockets connection to ${config.SERVICES_HOST} in your firewall/proxy`);
|
|
60
61
|
}
|
|
61
62
|
});
|
|
62
63
|
|
|
@@ -81,14 +82,14 @@ class BaseSocketServiceSocketIO {
|
|
|
81
82
|
});
|
|
82
83
|
|
|
83
84
|
this._socket.on('reconnect', () => {
|
|
84
|
-
logger.info(
|
|
85
|
+
logger.info('reconnect to socket and re-join to rooms');
|
|
85
86
|
this.joinToMultipleResults();
|
|
86
87
|
});
|
|
87
88
|
|
|
88
89
|
this._socket.on('connect', () => {
|
|
89
90
|
this.attempts = 0;
|
|
90
|
-
if(this.isAllowedWS === undefined) {
|
|
91
|
-
this.isAllowedWS = this._socket.io.engine.transport && this._socket.io.engine.transport.name ===
|
|
91
|
+
if (this.isAllowedWS === undefined) {
|
|
92
|
+
this.isAllowedWS = this._socket.io.engine.transport && this._socket.io.engine.transport.name === 'websocket';
|
|
92
93
|
}
|
|
93
94
|
if (this.onConnect) {
|
|
94
95
|
this.onConnect();
|
|
@@ -98,7 +99,7 @@ class BaseSocketServiceSocketIO {
|
|
|
98
99
|
|
|
99
100
|
initNewSocket(projectId, ns) {
|
|
100
101
|
const opts = {
|
|
101
|
-
query: {
|
|
102
|
+
query: { projectId },
|
|
102
103
|
requestTimeout: POLLING_TRANSPORT_TIMEOUT_MS,
|
|
103
104
|
transports: ['websocket'],
|
|
104
105
|
upgrade: false,
|
|
@@ -125,7 +126,7 @@ class BaseSocketServiceSocketIO {
|
|
|
125
126
|
|
|
126
127
|
init(projectId, ns) {
|
|
127
128
|
const opts = {
|
|
128
|
-
query: {
|
|
129
|
+
query: { projectId },
|
|
129
130
|
requestTimeout: POLLING_TRANSPORT_TIMEOUT_MS,
|
|
130
131
|
transports: ['websocket'],
|
|
131
132
|
upgrade: false,
|
|
@@ -136,7 +137,7 @@ class BaseSocketServiceSocketIO {
|
|
|
136
137
|
opts.ca = global.caFileContent;
|
|
137
138
|
}
|
|
138
139
|
|
|
139
|
-
if(global.proxyUri) {
|
|
140
|
+
if (global.proxyUri) {
|
|
140
141
|
opts.agent = new global.ProxyAgent(global.proxyUri);
|
|
141
142
|
}
|
|
142
143
|
|
|
@@ -146,23 +147,20 @@ class BaseSocketServiceSocketIO {
|
|
|
146
147
|
}
|
|
147
148
|
|
|
148
149
|
emitPromise(eventName, eventData) {
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
const emitAndWait = () => {
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
});
|
|
162
|
-
}).timeout(EMIT_PROMISE_TIMEOUT);
|
|
163
|
-
};
|
|
150
|
+
const errorneousEvents = {};
|
|
151
|
+
|
|
152
|
+
const emitAndWait = () => new Promise((resolve, reject) => {
|
|
153
|
+
this._socket.emit(eventName, eventData, data => {
|
|
154
|
+
if (data?.success) {
|
|
155
|
+
return resolve();
|
|
156
|
+
}
|
|
157
|
+
errorneousEvents[eventName] = eventData;
|
|
158
|
+
|
|
159
|
+
return reject(new Error('bad ack'));
|
|
160
|
+
});
|
|
161
|
+
}).timeout(EMIT_PROMISE_TIMEOUT);
|
|
164
162
|
|
|
165
|
-
this.
|
|
163
|
+
this.emitPromiseQueue = (this.emitPromiseQueue || Promise.resolve())
|
|
166
164
|
.then(() => pRetry(emitAndWait, { retries: 200, minTimeout: 3000 }))
|
|
167
165
|
.finally(() => {
|
|
168
166
|
if (Object.keys(errorneousEvents).length > 0) {
|
|
@@ -170,7 +168,7 @@ class BaseSocketServiceSocketIO {
|
|
|
170
168
|
}
|
|
171
169
|
});
|
|
172
170
|
|
|
173
|
-
return this.
|
|
171
|
+
return this.emitPromiseQueue;
|
|
174
172
|
}
|
|
175
173
|
}
|
|
176
174
|
|
|
@@ -1,12 +1,12 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
2
|
|
|
3
3
|
const RealDataServiceSocketIO = require('./realDataServiceSocketIO');
|
|
4
4
|
const socketService = require('./socketService');
|
|
5
5
|
|
|
6
|
-
const {socketEventTypes} = require('../constants');
|
|
6
|
+
const { socketEventTypes } = require('../constants');
|
|
7
7
|
const featureFlags = require('../featureFlags');
|
|
8
8
|
|
|
9
|
-
const {TEST_RESULT_CREATED, TEST_RESULT_UPDATED} = socketEventTypes;
|
|
9
|
+
const { TEST_RESULT_CREATED, TEST_RESULT_UPDATED } = socketEventTypes;
|
|
10
10
|
|
|
11
11
|
class RealDataService {
|
|
12
12
|
constructor() {
|
|
@@ -25,12 +25,13 @@ class RealDataService {
|
|
|
25
25
|
|
|
26
26
|
joinToTestResultsByRunId(runId, projectId) {
|
|
27
27
|
if (featureFlags.flags.useNewWSCLI.isEnabled()) {
|
|
28
|
-
return socketService.addFilter(runId, {runId}, [
|
|
28
|
+
return socketService.addFilter(runId, { runId }, [
|
|
29
29
|
TEST_RESULT_UPDATED,
|
|
30
|
-
TEST_RESULT_CREATED
|
|
30
|
+
TEST_RESULT_CREATED,
|
|
31
31
|
], true);
|
|
32
32
|
}
|
|
33
33
|
this.realDataServiceSocketIO.joinToTestResultsByRunId(runId, projectId);
|
|
34
|
+
return undefined;
|
|
34
35
|
}
|
|
35
36
|
|
|
36
37
|
stopListenToTestResultsByRunId(runId) {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
2
|
|
|
3
3
|
const BaseSocketService = require('./baseSocketServiceSocketIO');
|
|
4
4
|
|
|
@@ -8,7 +8,7 @@ class RealDataServiceSocketIO extends BaseSocketService {
|
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
emitJoinRoom(runId, projectId) {
|
|
11
|
-
this._socket.emit(
|
|
11
|
+
this._socket.emit('testResult:listen', { query: `projectId=${projectId}&runId=${runId}` });
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
joinToTestResultsByRunId(runId, projectId) {
|
|
@@ -18,7 +18,7 @@ class RealDataServiceSocketIO extends BaseSocketService {
|
|
|
18
18
|
|
|
19
19
|
stopListenToTestResultsByRunId(runId) {
|
|
20
20
|
this.leaveRoom(runId);
|
|
21
|
-
this._socket.emit(
|
|
21
|
+
this._socket.emit('testResult:listen:stop', {});
|
|
22
22
|
}
|
|
23
23
|
|
|
24
24
|
listenToTestResultsByRunId(cb) {
|
|
@@ -26,7 +26,7 @@ class RealDataServiceSocketIO extends BaseSocketService {
|
|
|
26
26
|
cb(data.data);
|
|
27
27
|
}
|
|
28
28
|
|
|
29
|
-
this._socket.on(
|
|
29
|
+
this._socket.on('testResult:changes', onDone.bind(this));
|
|
30
30
|
}
|
|
31
31
|
}
|
|
32
32
|
|
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
let remoteStepServiceSocketIO; // required lazily since it takes 150ms to load
|
|
2
2
|
const socketService = require('./socketService');
|
|
3
3
|
|
|
4
|
-
const {socketEventTypes} = require('../constants');
|
|
5
|
-
|
|
4
|
+
const { socketEventTypes } = require('../constants');
|
|
5
|
+
|
|
6
|
+
const { REMOTE_STEP_SAVED } = socketEventTypes;
|
|
6
7
|
const featureFlags = require('../featureFlags');
|
|
7
8
|
const Promise = require('bluebird');
|
|
8
9
|
|
|
@@ -17,7 +18,7 @@ class RemoteStepService {
|
|
|
17
18
|
|
|
18
19
|
joinToRemoteStep(resultId) {
|
|
19
20
|
if (featureFlags.flags.useNewWSCLI.isEnabled()) {
|
|
20
|
-
return socketService.addFilter(`${resultId}:remoteStep`, {resultId}, [REMOTE_STEP_SAVED]);
|
|
21
|
+
return socketService.addFilter(`${resultId}:remoteStep`, { resultId }, [REMOTE_STEP_SAVED]);
|
|
21
22
|
}
|
|
22
23
|
return remoteStepServiceSocketIO.joinToRemoteStep(resultId);
|
|
23
24
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
'use strict';
|
|
2
2
|
|
|
3
3
|
const Promise = require('bluebird');
|
|
4
4
|
const BaseSocketService = require('./baseSocketServiceSocketIO');
|
|
@@ -10,15 +10,15 @@ class RemoteStepServiceSocketIO extends BaseSocketService {
|
|
|
10
10
|
}
|
|
11
11
|
|
|
12
12
|
emitJoinRoom(resultId) {
|
|
13
|
-
return this.emitPromise(
|
|
13
|
+
return this.emitPromise('remoteStep:join', { resultId });
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
emitLeaveRoom(resultId) {
|
|
17
|
-
return this.emitPromise(
|
|
17
|
+
return this.emitPromise('remoteStep:leave', { resultId });
|
|
18
18
|
}
|
|
19
19
|
|
|
20
20
|
joinToRemoteStep(resultId) {
|
|
21
|
-
if(this.rooms[resultId]) {
|
|
21
|
+
if (this.rooms[resultId]) {
|
|
22
22
|
return Promise.resolve();
|
|
23
23
|
}
|
|
24
24
|
this.joinRoom(resultId);
|
|
@@ -26,17 +26,16 @@ class RemoteStepServiceSocketIO extends BaseSocketService {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
saveRemoteStep(resultId, stepId, remoteStep) {
|
|
29
|
-
return this.emitPromise(
|
|
29
|
+
return this.emitPromise('remoteStep:save', {
|
|
30
30
|
resultId,
|
|
31
31
|
stepId,
|
|
32
|
-
remoteStep
|
|
32
|
+
remoteStep,
|
|
33
33
|
});
|
|
34
34
|
}
|
|
35
35
|
|
|
36
36
|
listenToRemoteStep(resultId, onRemoteStep) {
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
this._socket.off("remoteStep:saved", this.listerers[resultId]);
|
|
37
|
+
if (this.listerers[resultId]) {
|
|
38
|
+
this._socket.off('remoteStep:saved', this.listerers[resultId]);
|
|
40
39
|
delete this.listerers[resultId];
|
|
41
40
|
}
|
|
42
41
|
|
|
@@ -45,16 +44,16 @@ class RemoteStepServiceSocketIO extends BaseSocketService {
|
|
|
45
44
|
onRemoteStep(data.remoteStep);
|
|
46
45
|
}
|
|
47
46
|
};
|
|
48
|
-
this._socket.on(
|
|
47
|
+
this._socket.on('remoteStep:saved', this.listerers[resultId]);
|
|
49
48
|
}
|
|
50
49
|
|
|
51
50
|
unlistenToRemoteStep(resultId) {
|
|
52
|
-
if(!this.listerers[resultId]) {
|
|
51
|
+
if (!this.listerers[resultId]) {
|
|
53
52
|
return Promise.resolve();
|
|
54
53
|
}
|
|
55
54
|
|
|
56
55
|
this.leaveRoom(resultId);
|
|
57
|
-
this._socket.off(
|
|
56
|
+
this._socket.off('remoteStep:saved', this.listerers[resultId]);
|
|
58
57
|
delete this.listerers[resultId];
|
|
59
58
|
return this.emitLeaveRoom(resultId);
|
|
60
59
|
}
|