@testim/testim-cli 3.233.0 → 3.236.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/cliJsCode/service.js +4 -38
- package/agent/server.js +2 -2
- package/cli.js +0 -2
- package/cliAgentMode.js +129 -15
- package/commons/chromedriverWrapper.js +1 -0
- package/commons/featureFlags.js +1 -0
- package/commons/prepareRunnerAndTestimStartUtils.js +7 -3
- package/commons/testimCloudflare.js +16 -13
- package/commons/testimCloudflare.test.js +162 -0
- package/commons/testimNgrok.js +6 -4
- package/commons/testimNgrok.test.js +140 -0
- package/commons/testimTunnel.js +5 -5
- package/commons/testimTunnel.test.js +69 -0
- package/npm-shrinkwrap.json +261 -245
- package/package.json +1 -2
- package/player/stepActions/inputFileStepAction.js +23 -14
- package/player/stepActions/textValidationStepAction.js +3 -0
- package/player/webdriver.js +10 -1
- package/processHandler.js +9 -4
- package/runOptions.js +70 -70
- package/runOptionsAgentFlow.js +5 -0
- package/runner.js +1 -2
- package/runners/ParallelWorkerManager.js +0 -1
- package/runners/TestPlanRunner.js +8 -9
- package/services/lambdatestService.js +13 -9
- package/services/lambdatestService.test.js +259 -0
- package/testRunStatus.js +34 -5
|
@@ -20,7 +20,6 @@ const { getSuite, calcTestResultStatus, validateConfig } = require('./runnerUtil
|
|
|
20
20
|
const { StopRunOnError, ArgError } = require('../errors');
|
|
21
21
|
const Logger = require('../commons/logger');
|
|
22
22
|
const perf = require('../commons/performance-logger');
|
|
23
|
-
const featureFlags = require('../commons/featureFlags');
|
|
24
23
|
|
|
25
24
|
const guid = utils.guid;
|
|
26
25
|
const logger = Logger.getLogger('test-plan-runner');
|
|
@@ -35,14 +34,14 @@ class TestPlanRunner {
|
|
|
35
34
|
const executionResults = {};
|
|
36
35
|
const authData = testimCustomToken.getTokenV3UserData();
|
|
37
36
|
|
|
38
|
-
const runBeforeTests = (
|
|
37
|
+
const runBeforeTests = () => {
|
|
39
38
|
const workerCount = 1;
|
|
40
39
|
const stopOnError = true;
|
|
41
40
|
return this.workerManager.runTests(beforeTests, testStatus, executionId, executionName, tpOptions, branchToUse, authData, workerCount, stopOnError)
|
|
42
41
|
.then(beforeTestsResults => Object.assign(executionResults, beforeTestsResults));
|
|
43
42
|
};
|
|
44
43
|
|
|
45
|
-
const runTestPlanTests = (
|
|
44
|
+
const runTestPlanTests = () => {
|
|
46
45
|
const workerCount = config.TESTIM_CONCURRENT_WORKER_COUNT || tpOptions.parallel;
|
|
47
46
|
const stopOnError = false;
|
|
48
47
|
perf.log('right before this.workerManager.runTests');
|
|
@@ -51,30 +50,30 @@ class TestPlanRunner {
|
|
|
51
50
|
.then(testsResults => Object.assign(executionResults, testsResults));
|
|
52
51
|
};
|
|
53
52
|
|
|
54
|
-
const runAfterTests = (
|
|
53
|
+
const runAfterTests = () => {
|
|
55
54
|
const workerCount = 1;
|
|
56
55
|
const stopOnError = false;
|
|
57
56
|
return this.workerManager.runTests(afterTests, testStatus, executionId, executionName, tpOptions, branchToUse, authData, workerCount, stopOnError)
|
|
58
57
|
.then(afterTestsResults => Object.assign(executionResults, afterTestsResults));
|
|
59
58
|
};
|
|
60
59
|
|
|
61
|
-
function catchBeforeTestsFailed(
|
|
60
|
+
function catchBeforeTestsFailed() {
|
|
62
61
|
return testStatus.markAllQueuedTests(executionId, constants.runnerTestStatus.ABORTED, 'aborted', false);
|
|
63
62
|
}
|
|
64
63
|
|
|
65
64
|
const sessionType = utils.getSessionType(tpOptions);
|
|
66
65
|
analyticsService.analyticsExecsStart({ authData, executionId, projectId: tpOptions.project, sessionType });
|
|
67
66
|
perf.log('right before runBeforeTests');
|
|
68
|
-
return runBeforeTests(
|
|
67
|
+
return runBeforeTests()
|
|
69
68
|
.log('right before runTestPlanTests')
|
|
70
|
-
.then(() => runTestPlanTests(
|
|
69
|
+
.then(() => runTestPlanTests())
|
|
71
70
|
.log('right after runTestPlanTests')
|
|
72
|
-
.then(() => runAfterTests(
|
|
71
|
+
.then(() => runAfterTests())
|
|
73
72
|
.then(() => executionResults)
|
|
74
73
|
.catch(err => {
|
|
75
74
|
logger.error('error running test plan', { err });
|
|
76
75
|
if (err instanceof StopRunOnError) {
|
|
77
|
-
return catchBeforeTestsFailed(
|
|
76
|
+
return catchBeforeTestsFailed();
|
|
78
77
|
}
|
|
79
78
|
throw err;
|
|
80
79
|
})
|
|
@@ -1,13 +1,12 @@
|
|
|
1
1
|
const os = require('os');
|
|
2
|
-
const
|
|
2
|
+
const childProcess = require('child_process');
|
|
3
3
|
const Promise = require('bluebird');
|
|
4
4
|
const fse = require('fs-extra');
|
|
5
5
|
const portfinder = require('portfinder');
|
|
6
6
|
const ms = require('ms');
|
|
7
7
|
|
|
8
|
-
const {
|
|
9
|
-
|
|
10
|
-
} = require('../utils');
|
|
8
|
+
const { guid, isURL } = require('../utils');
|
|
9
|
+
const utils = require('../utils');
|
|
11
10
|
const { gridTypes, CLI_MODE } = require('../commons/constants');
|
|
12
11
|
const httpRequest = require('../commons/httpRequest');
|
|
13
12
|
const { ArgError } = require('../errors');
|
|
@@ -86,8 +85,8 @@ class LambdatestService {
|
|
|
86
85
|
throw new Error(`tunnel on ${os.platform() + os.arch()} platform is not supported.`);
|
|
87
86
|
}
|
|
88
87
|
const zipLocation = `${LT_TUNNEL_BINARY_DIRECTORY}.zip`;
|
|
89
|
-
await downloadAndSave(`${LT_TUNNEL_BINARY_ORIGIN}/${downloadUrl}`, zipLocation);
|
|
90
|
-
await unzipFile(zipLocation, LT_TUNNEL_BINARY_DIRECTORY);
|
|
88
|
+
await utils.downloadAndSave(`${LT_TUNNEL_BINARY_ORIGIN}/${downloadUrl}`, zipLocation);
|
|
89
|
+
await utils.unzipFile(zipLocation, LT_TUNNEL_BINARY_DIRECTORY);
|
|
91
90
|
}
|
|
92
91
|
|
|
93
92
|
static async connectTunnel(runnerOptions) {
|
|
@@ -136,7 +135,11 @@ class LambdatestService {
|
|
|
136
135
|
}
|
|
137
136
|
}
|
|
138
137
|
|
|
139
|
-
|
|
138
|
+
if (runnerOptions.externalLambdatestMitm) {
|
|
139
|
+
tunnelArgs = [...tunnelArgs, '--mitm'];
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
LambdatestService.tunnel = childProcess.spawn('./LT', tunnelArgs, { cwd: LT_TUNNEL_BINARY_DIRECTORY });
|
|
140
143
|
|
|
141
144
|
let stdoutResult = '';
|
|
142
145
|
let stderrResult = '';
|
|
@@ -151,7 +154,7 @@ class LambdatestService {
|
|
|
151
154
|
|
|
152
155
|
// verify that LT tunnel strated successfully
|
|
153
156
|
try {
|
|
154
|
-
const ltInfo = await runWithRetries(() => httpRequest.get(`http://127.0.0.1:${infoAPIPort}/api/v1.0/info`, {}, {}, undefined, { skipProxy: true }), 30, 2000);
|
|
157
|
+
const ltInfo = await utils.runWithRetries(() => httpRequest.get(`http://127.0.0.1:${infoAPIPort}/api/v1.0/info`, {}, {}, undefined, { skipProxy: true }), 30, 2000);
|
|
155
158
|
logger.info('LT tunnel info', ltInfo);
|
|
156
159
|
} catch (err) {
|
|
157
160
|
logger.error('Failed to start LT tunnel', { err, stdoutResult, stderrResult });
|
|
@@ -166,7 +169,7 @@ class LambdatestService {
|
|
|
166
169
|
return new Promise((resolve, reject) => {
|
|
167
170
|
LambdatestService.tunnel.on('close', (code) => {
|
|
168
171
|
if (code) {
|
|
169
|
-
reject();
|
|
172
|
+
reject(new Error(`tunnel process exited with code ${code}`));
|
|
170
173
|
}
|
|
171
174
|
resolve();
|
|
172
175
|
});
|
|
@@ -207,6 +210,7 @@ class LambdatestService {
|
|
|
207
210
|
build: executionId,
|
|
208
211
|
name: `${testResultId} - ${testName}`,
|
|
209
212
|
platform: LambdatestService.lambdatestConfig.PLATFORM,
|
|
213
|
+
// eslint-disable-next-line camelcase
|
|
210
214
|
selenium_version: LambdatestService.lambdatestConfig.SELENIUM_VERSION,
|
|
211
215
|
resolution: LambdatestService.lambdatestConfig.RESOLUTION,
|
|
212
216
|
timezone: LambdatestService.lambdatestConfig.TIMEZONE,
|
|
@@ -1,11 +1,38 @@
|
|
|
1
1
|
const { expect, sinon } = require('../../test/utils/testUtils');
|
|
2
2
|
const servicesApi = require('../commons/testimServicesApi');
|
|
3
|
+
const httpRequest = require('../commons/httpRequest');
|
|
3
4
|
const LambdatestService = require('./lambdatestService');
|
|
5
|
+
const utils = require('../utils');
|
|
6
|
+
const fse = require('fs-extra');
|
|
7
|
+
const os = require('os');
|
|
8
|
+
const childProcess = require('child_process');
|
|
9
|
+
const EventEmitter = require('events');
|
|
10
|
+
const portfinder = require('portfinder');
|
|
11
|
+
const { getExtensionsUrl } = require('../runOptionsUtils');
|
|
12
|
+
|
|
13
|
+
class Process extends EventEmitter {
|
|
14
|
+
constructor() {
|
|
15
|
+
super();
|
|
16
|
+
this.stdout = new EventEmitter();
|
|
17
|
+
this.stderr = new EventEmitter();
|
|
18
|
+
}
|
|
19
|
+
setCode(code) {
|
|
20
|
+
this.code = code;
|
|
21
|
+
}
|
|
22
|
+
kill() {
|
|
23
|
+
this.emit('close', this.code);
|
|
24
|
+
}
|
|
25
|
+
}
|
|
4
26
|
|
|
5
27
|
describe('LambdatestService', () => {
|
|
28
|
+
let sandbox;
|
|
6
29
|
let lambdatestService;
|
|
7
30
|
beforeEach(() => {
|
|
8
31
|
lambdatestService = new LambdatestService();
|
|
32
|
+
sandbox = sinon.createSandbox();
|
|
33
|
+
});
|
|
34
|
+
afterEach(() => {
|
|
35
|
+
sandbox.restore();
|
|
9
36
|
});
|
|
10
37
|
|
|
11
38
|
describe('isLambdatestGrid', () => {
|
|
@@ -86,8 +113,240 @@ describe('LambdatestService', () => {
|
|
|
86
113
|
lambdatestService.isActive = false;
|
|
87
114
|
expect(lambdatestService.getSessionRetries).to.be.equal(null);
|
|
88
115
|
});
|
|
116
|
+
|
|
117
|
+
it('should not return lt special selenium capabilities when inactove', () => {
|
|
118
|
+
lambdatestService.isActive = false;
|
|
119
|
+
expect(lambdatestService.getCapabilities({})).to.eql({});
|
|
120
|
+
});
|
|
121
|
+
|
|
122
|
+
it('should return lt selenium capabilities', () => {
|
|
123
|
+
const browser = utils.guid();
|
|
124
|
+
const executionId = utils.guid();
|
|
125
|
+
const testResultId = utils.guid();
|
|
126
|
+
const testName = utils.guid();
|
|
127
|
+
|
|
128
|
+
lambdatestService.isActive = true;
|
|
129
|
+
LambdatestService.lambdatestConfig = {
|
|
130
|
+
CAPABILITIES: { [browser]: { specificBrowserCaps: 123 } },
|
|
131
|
+
};
|
|
132
|
+
|
|
133
|
+
expect(lambdatestService.getCapabilities({}, browser, executionId, testResultId, testName)).to.shallowDeepEqual({
|
|
134
|
+
build: executionId,
|
|
135
|
+
name: `${testResultId} - ${testName}`,
|
|
136
|
+
platform: LambdatestService.lambdatestConfig.PLATFORM,
|
|
137
|
+
// eslint-disable-next-line camelcase
|
|
138
|
+
selenium_version: LambdatestService.lambdatestConfig.SELENIUM_VERSION,
|
|
139
|
+
resolution: LambdatestService.lambdatestConfig.RESOLUTION,
|
|
140
|
+
timezone: LambdatestService.lambdatestConfig.TIMEZONE,
|
|
141
|
+
specificBrowserCaps: 123,
|
|
142
|
+
console: true,
|
|
143
|
+
queueTimeout: 300,
|
|
144
|
+
});
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
it('should return lt tunnel name as part of selenium capabilities', () => {
|
|
148
|
+
lambdatestService.isActive = true;
|
|
149
|
+
LambdatestService.lambdatestConfig = { CAPABILITIES: {} };
|
|
150
|
+
LambdatestService.tunnelName = utils.guid();
|
|
151
|
+
|
|
152
|
+
expect(lambdatestService.getCapabilities({})).to.shallowDeepEqual({
|
|
153
|
+
tunnel: true,
|
|
154
|
+
tunnelName: LambdatestService.tunnelName,
|
|
155
|
+
});
|
|
156
|
+
});
|
|
157
|
+
|
|
158
|
+
it('should load testim extension when it is not set', () => {
|
|
159
|
+
lambdatestService.isActive = true;
|
|
160
|
+
LambdatestService.lambdatestConfig = { CAPABILITIES: {} };
|
|
161
|
+
LambdatestService.tunnelName = utils.guid();
|
|
162
|
+
|
|
163
|
+
expect(lambdatestService.getCapabilities({ mode: 'extension' }, 'chrome')).to.shallowDeepEqual({ loadExtension: [getExtensionsUrl({}, true).chrome] });
|
|
164
|
+
expect(lambdatestService.getCapabilities({ mode: 'extension' }, 'somOtherBrowser')).to.shallowDeepEqual({ loadExtension: [] });
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
it('should load testim extension when passing extensionPath flag', () => {
|
|
168
|
+
lambdatestService.isActive = true;
|
|
169
|
+
LambdatestService.lambdatestConfig = { CAPABILITIES: {} };
|
|
170
|
+
LambdatestService.tunnelName = utils.guid();
|
|
171
|
+
|
|
172
|
+
const extensionPath = 'http://localhost:1234/extension.zip';
|
|
173
|
+
expect(lambdatestService.getCapabilities({ mode: 'extension', extensionPath })).to.shallowDeepEqual({ loadExtension: [extensionPath] });
|
|
174
|
+
});
|
|
175
|
+
|
|
176
|
+
it('should load testim extension when passing installCustomExtension flag', () => {
|
|
177
|
+
lambdatestService.isActive = true;
|
|
178
|
+
LambdatestService.lambdatestConfig = { CAPABILITIES: {} };
|
|
179
|
+
LambdatestService.tunnelName = utils.guid();
|
|
180
|
+
|
|
181
|
+
const installCustomExtension = 'http://localhost:1234/extension.zip';
|
|
182
|
+
expect(lambdatestService.getCapabilities({ mode: 'extension', installCustomExtension })).to.shallowDeepEqual({ loadExtension: [installCustomExtension] });
|
|
183
|
+
});
|
|
184
|
+
});
|
|
185
|
+
|
|
186
|
+
describe('prepareTunnel', () => {
|
|
187
|
+
it('should do nothing when tunnel binary already exists', async () => {
|
|
188
|
+
sandbox.stub(fse, 'pathExists').resolves(true);
|
|
189
|
+
const chmod = sandbox.stub(fse, 'chmodSync');
|
|
190
|
+
await LambdatestService.prepareTunnel();
|
|
191
|
+
expect(chmod).not.to.have.been.called;
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it('should throw when unsupported os', async () => {
|
|
195
|
+
sandbox.stub(fse, 'pathExists').resolves(false);
|
|
196
|
+
sandbox.stub(os, 'platform').returns('wtf');
|
|
197
|
+
sandbox.stub(os, 'arch').returns('wtf');
|
|
198
|
+
|
|
199
|
+
await expect(LambdatestService.prepareTunnel()).to.be.rejectedWith(Error, 'tunnel on wtfwtf platform is not supported.');
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
it('should download and extract tunnel binary', async () => {
|
|
203
|
+
sandbox.stub(fse, 'pathExists').resolves(false);
|
|
204
|
+
sandbox.stub(os, 'platform').returns('win32');
|
|
205
|
+
sandbox.stub(os, 'arch').returns('x64');
|
|
206
|
+
|
|
207
|
+
const download = sandbox.stub(utils, 'downloadAndSave');
|
|
208
|
+
const unzip = sandbox.stub(utils, 'unzipFile').resolves();
|
|
209
|
+
|
|
210
|
+
await LambdatestService.prepareTunnel();
|
|
211
|
+
sinon.assert.calledOnce(unzip);
|
|
212
|
+
sinon.assert.calledOnce(download);
|
|
213
|
+
expect(download.args[0][0]).to.startWith('https://downloads.lambdatest.com/tunnel/');
|
|
214
|
+
});
|
|
89
215
|
});
|
|
90
216
|
|
|
91
217
|
describe('connectTunnel', () => {
|
|
218
|
+
let prepareTunnelStub;
|
|
219
|
+
let spawnStub;
|
|
220
|
+
let credentials;
|
|
221
|
+
let httpGetStub;
|
|
222
|
+
let processMock;
|
|
223
|
+
|
|
224
|
+
beforeEach(() => {
|
|
225
|
+
processMock = new Process();
|
|
226
|
+
credentials = { gridUsername: utils.guid(), gridPassword: utils.guid() };
|
|
227
|
+
sandbox.stub(portfinder, 'getPortPromise').resolves(1234);
|
|
228
|
+
prepareTunnelStub = sandbox.stub(LambdatestService, 'prepareTunnel');
|
|
229
|
+
spawnStub = sandbox.stub(childProcess, 'spawn').returns(processMock);
|
|
230
|
+
httpGetStub = sandbox.stub(httpRequest, 'get').resolves({});
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
it('should do nothing when using externalLambdatestTunnelId', async () => {
|
|
234
|
+
await LambdatestService.connectTunnel({ externalLambdatestTunnelId: 123 });
|
|
235
|
+
sinon.assert.neverCalledWith(prepareTunnelStub);
|
|
236
|
+
sinon.assert.neverCalledWith(spawnStub);
|
|
237
|
+
});
|
|
238
|
+
|
|
239
|
+
it('should prepare the tunnel', async () => {
|
|
240
|
+
await LambdatestService.connectTunnel({ ...credentials });
|
|
241
|
+
sinon.assert.calledOnce(prepareTunnelStub);
|
|
242
|
+
});
|
|
243
|
+
|
|
244
|
+
it('should reject when no credentials', async () => {
|
|
245
|
+
await expect(LambdatestService.connectTunnel({ })).to.be.rejectedWith(Error, 'tunnel requires username and password');
|
|
246
|
+
});
|
|
247
|
+
|
|
248
|
+
it('should spawn the tunnel process', async () => {
|
|
249
|
+
await LambdatestService.connectTunnel({ ...credentials });
|
|
250
|
+
sinon.assert.calledOnce(spawnStub);
|
|
251
|
+
expect(spawnStub.args[0][1]).to.eql([
|
|
252
|
+
'--tunnelName', LambdatestService.tunnelName, '--infoAPIPort', 1234,
|
|
253
|
+
'--user', credentials.gridUsername, '--key', credentials.gridPassword,
|
|
254
|
+
]);
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
it('should accept tunnelUser and tunnelKey on gridData', async () => {
|
|
258
|
+
credentials = { gridData: { tunnelUser: utils.guid(), tunnelKey: utils.guid() } };
|
|
259
|
+
await LambdatestService.connectTunnel({ ...credentials });
|
|
260
|
+
sinon.assert.calledOnce(spawnStub);
|
|
261
|
+
expect(spawnStub.args[0][1]).to.eql([
|
|
262
|
+
'--tunnelName', LambdatestService.tunnelName, '--infoAPIPort', 1234,
|
|
263
|
+
'--user', credentials.gridData.tunnelUser, '--key', credentials.gridData.tunnelKey,
|
|
264
|
+
]);
|
|
265
|
+
});
|
|
266
|
+
|
|
267
|
+
it('should allow using externalLambdatestUseWss', async () => {
|
|
268
|
+
await LambdatestService.connectTunnel({ ...credentials, externalLambdatestUseWss: true });
|
|
269
|
+
sinon.assert.calledOnce(spawnStub);
|
|
270
|
+
expect(spawnStub.args[0][1].join(' ')).to.contain('--mode ws');
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
it('should allow using proxyUri', async () => {
|
|
274
|
+
global.proxyUri = 'http://localhost';
|
|
275
|
+
await LambdatestService.connectTunnel({ ...credentials });
|
|
276
|
+
sinon.assert.calledOnce(spawnStub);
|
|
277
|
+
expect(spawnStub.args[0][1].join(' ')).to.contain('--proxy-host localhost');
|
|
278
|
+
global.proxyUri = undefined;
|
|
279
|
+
});
|
|
280
|
+
|
|
281
|
+
it('should allow using proxyUri port and credentials', async () => {
|
|
282
|
+
global.proxyUri = 'http://user:pass@localhost:1234';
|
|
283
|
+
await LambdatestService.connectTunnel({ ...credentials });
|
|
284
|
+
sinon.assert.calledOnce(spawnStub);
|
|
285
|
+
expect(spawnStub.args[0][1].join(' ')).to.contain('--proxy-host localhost');
|
|
286
|
+
expect(spawnStub.args[0][1].join(' ')).to.contain('--proxy-port 1234');
|
|
287
|
+
expect(spawnStub.args[0][1].join(' ')).to.contain('--proxy-user user');
|
|
288
|
+
expect(spawnStub.args[0][1].join(' ')).to.contain('--proxy-pass pass');
|
|
289
|
+
global.proxyUri = undefined;
|
|
290
|
+
});
|
|
291
|
+
|
|
292
|
+
it('should throw when proxyUri is invalid', async () => {
|
|
293
|
+
global.proxyUri = 'i am invalid';
|
|
294
|
+
await expect(LambdatestService.connectTunnel({ ...credentials })).to.be.rejectedWith(Error, 'proxy url is invalid');
|
|
295
|
+
global.proxyUri = undefined;
|
|
296
|
+
});
|
|
297
|
+
|
|
298
|
+
it('should allow using externalLambdatestDisableAutomationTunneling', async () => {
|
|
299
|
+
await LambdatestService.connectTunnel({ ...credentials, externalLambdatestDisableAutomationTunneling: true });
|
|
300
|
+
sinon.assert.calledOnce(spawnStub);
|
|
301
|
+
expect(spawnStub.args[0][1].join(' ')).to.contain('--bypassHosts run.testim.io,services.testim.io,api.coralogix.com,conf.rollout.io,statestore.rollout.io,push.rollout.io,analytic.rollout.io,res.cloudinary.com');
|
|
302
|
+
});
|
|
303
|
+
|
|
304
|
+
it('should allow using externalLambdatestMitm', async () => {
|
|
305
|
+
await LambdatestService.connectTunnel({ ...credentials, externalLambdatestMitm: true });
|
|
306
|
+
sinon.assert.calledOnce(spawnStub);
|
|
307
|
+
expect(spawnStub.args[0][1].join(' ')).to.contain('--mitm');
|
|
308
|
+
});
|
|
309
|
+
|
|
310
|
+
it('should verify tunnel started', async () => {
|
|
311
|
+
await LambdatestService.connectTunnel({ ...credentials });
|
|
312
|
+
sinon.assert.calledOnce(httpGetStub);
|
|
313
|
+
});
|
|
314
|
+
it('should throw when tunnel did not start', async () => {
|
|
315
|
+
sandbox.stub(utils, 'runWithRetries').rejects(new Error('tunnel did not start'));
|
|
316
|
+
await expect(LambdatestService.connectTunnel({ ...credentials })).to.be.rejectedWith(Error, 'tunnel did not start');
|
|
317
|
+
processMock.stdout.emit('data', '');
|
|
318
|
+
processMock.stderr.emit('data', '');
|
|
319
|
+
});
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
describe('disconnectTunnel', () => {
|
|
323
|
+
let processMock;
|
|
324
|
+
let killStub;
|
|
325
|
+
|
|
326
|
+
beforeEach(() => {
|
|
327
|
+
processMock = new Process();
|
|
328
|
+
killStub = sandbox.stub(processMock, 'kill').callThrough();
|
|
329
|
+
sandbox.stub(childProcess, 'spawn').returns(processMock);
|
|
330
|
+
sandbox.stub(LambdatestService, 'prepareTunnel');
|
|
331
|
+
sandbox.stub(httpRequest, 'get').resolves({});
|
|
332
|
+
});
|
|
333
|
+
|
|
334
|
+
it('should kill the tunnel', async () => {
|
|
335
|
+
await LambdatestService.connectTunnel({ tunnel: true, company: {}, gridUsername: utils.guid(), gridPassword: utils.guid() });
|
|
336
|
+
await LambdatestService.disconnectTunnel({ company: {} });
|
|
337
|
+
sinon.assert.calledOnce(killStub);
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
it('should reject when killing the tunnel fails', async () => {
|
|
341
|
+
processMock.setCode(1);
|
|
342
|
+
await LambdatestService.connectTunnel({ tunnel: true, company: {}, gridUsername: utils.guid(), gridPassword: utils.guid() });
|
|
343
|
+
await expect(LambdatestService.disconnectTunnel({ company: {} })).to.be.rejectedWith(Error);
|
|
344
|
+
sinon.assert.calledOnce(killStub);
|
|
345
|
+
});
|
|
346
|
+
|
|
347
|
+
it('should do nothing when using externalLambdatestTunnelId', async () => {
|
|
348
|
+
await LambdatestService.disconnectTunnel({ externalLambdatestTunnelId: 123 });
|
|
349
|
+
sinon.assert.neverCalledWith(killStub);
|
|
350
|
+
});
|
|
92
351
|
});
|
|
93
352
|
});
|
package/testRunStatus.js
CHANGED
|
@@ -174,7 +174,21 @@ RunStatus.prototype.testStartReport = function (test, executionId, testRetryKey)
|
|
|
174
174
|
}
|
|
175
175
|
return runHook(this.options.beforeTest, Object.assign({}, test, { exportsGlobal: this.exportsGlobal }), this.options.userData.loginData.token)
|
|
176
176
|
.then(async params => {
|
|
177
|
-
|
|
177
|
+
// Temporary Sapiens log (SUP-3192)
|
|
178
|
+
if (this.options.projectData && this.options.projectData.projectId === 'fZ63D61PRQQVvvtGY6Ue' && this.options.suites && this.options.suites.includes('Sanity')) {
|
|
179
|
+
logger.info('testRunStatus - testStartReport', {
|
|
180
|
+
'test.config.testData': test.config.testData,
|
|
181
|
+
'this.exportsGlobal': this.exportsGlobal,
|
|
182
|
+
'this.fileUserParamsData': this.fileUserParamsData,
|
|
183
|
+
'this.beforeSuiteParams': this.beforeSuiteParams,
|
|
184
|
+
params,
|
|
185
|
+
executionId,
|
|
186
|
+
'test.testId': test.testId,
|
|
187
|
+
'test.resultId': test.resultId,
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
test.config.testData = Object.assign({}, test.config.testData, this.exportsGlobal, this.fileUserParamsData, this.beforeSuiteParams, params);
|
|
191
|
+
this.options.runParams[test.resultId] = test.config.testData;
|
|
178
192
|
test.startTime = Date.now();
|
|
179
193
|
await this.updateTestStatusRunning(test, executionId, testRetryKey);
|
|
180
194
|
|
|
@@ -234,8 +248,10 @@ RunStatus.prototype.testEnd = function (wid, result, executionId, sessionId, isR
|
|
|
234
248
|
const duration = (result.endTime - result.startTime) || 0;
|
|
235
249
|
test.sessionId = sessionId;
|
|
236
250
|
test.startTime = result.startTime || test.startTime || Date.now();
|
|
237
|
-
test.duration =
|
|
238
|
-
result.
|
|
251
|
+
test.duration = duration;
|
|
252
|
+
result.duration = duration;
|
|
253
|
+
test.failureReason = result.failureReason || result.reason;
|
|
254
|
+
result.failureReason = test.failureReason;
|
|
239
255
|
test.failurePath = result.failurePath;
|
|
240
256
|
test.resultId = result.resultId;
|
|
241
257
|
test.success = result.success;
|
|
@@ -245,8 +261,9 @@ RunStatus.prototype.testEnd = function (wid, result, executionId, sessionId, isR
|
|
|
245
261
|
}
|
|
246
262
|
|
|
247
263
|
test.resultUrl = utils.getTestUrl(this.options.editorUrl, this.options.project, test.testId, test.resultId, this.branchToUse);
|
|
264
|
+
test.status = this.calcResultText(result);
|
|
248
265
|
|
|
249
|
-
|
|
266
|
+
result.status = test.status;
|
|
250
267
|
result.name = test.name;
|
|
251
268
|
result.testStatus = test.testStatus;
|
|
252
269
|
result.testId = result.testId || test.testId;
|
|
@@ -263,7 +280,19 @@ RunStatus.prototype.testEnd = function (wid, result, executionId, sessionId, isR
|
|
|
263
280
|
const isCodeMode = this.options.files.length > 0;
|
|
264
281
|
reporter.onTestFinished(test, wid, isRerun, isCodeMode);
|
|
265
282
|
|
|
266
|
-
|
|
283
|
+
const afterMerge = Object.assign({}, this.exportsGlobal, result.exportsGlobal);
|
|
284
|
+
// Temporary Sapiens log (SUP-3192)
|
|
285
|
+
if (this.options.projectData && this.options.projectData.projectId === 'fZ63D61PRQQVvvtGY6Ue' && this.options.suites && this.options.suites.includes('Sanity')) {
|
|
286
|
+
logger.info('testRunStatus - testEnd', {
|
|
287
|
+
'this.exportsGlobal': this.exportsGlobal,
|
|
288
|
+
'result.exportsGlobal': result.exportsGlobal,
|
|
289
|
+
afterMerge,
|
|
290
|
+
executionId,
|
|
291
|
+
'test.testId': test.testId,
|
|
292
|
+
'test.resultId': test.resultId,
|
|
293
|
+
});
|
|
294
|
+
}
|
|
295
|
+
this.exportsGlobal = afterMerge;
|
|
267
296
|
return test;
|
|
268
297
|
};
|
|
269
298
|
|