@testim/testim-cli 3.221.0 → 3.225.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/commons/testimDesiredCapabilitiesBuilder.js +6 -1
- package/commons/testimServicesApi.js +6 -3
- package/npm-shrinkwrap.json +385 -228
- package/package.json +1 -1
- package/reports/debugReporter.js +6 -5
- package/runOptions.js +22 -10
- package/runner.js +1 -1
- package/runners/TestPlanRunner.js +5 -1
- package/runners/runnerUtils.js +1 -0
- package/services/gridService.js +26 -13
- package/services/gridService.test.js +6 -13
- package/testRunStatus.js +1 -0
package/package.json
CHANGED
package/reports/debugReporter.js
CHANGED
|
@@ -25,11 +25,12 @@ DebugReporter.prototype.onTestStarted = function (test, workerId) {
|
|
|
25
25
|
};
|
|
26
26
|
|
|
27
27
|
DebugReporter.prototype.onTestFinished = function (test, workerId) {
|
|
28
|
-
const
|
|
29
|
-
const
|
|
30
|
-
const
|
|
31
|
-
const
|
|
32
|
-
const
|
|
28
|
+
const gridData = this.options.gridData || {};
|
|
29
|
+
const provider = gridData.provider;
|
|
30
|
+
const host = gridData.host;
|
|
31
|
+
const gridId = gridData.gridId;
|
|
32
|
+
const gridType = gridData.type;
|
|
33
|
+
const failedGetBrowserAttempts = gridData.failedGetBrowserAttempts;
|
|
33
34
|
logger.info('Test Finished', {
|
|
34
35
|
testId: test.testId,
|
|
35
36
|
testName: test.name,
|
package/runOptions.js
CHANGED
|
@@ -158,16 +158,16 @@ program
|
|
|
158
158
|
.option('-o --options-file [options-file.json]', '')
|
|
159
159
|
.option('-c --config-file [config-file.js]', '')
|
|
160
160
|
.option('--test-config [test-config]', 'test config name to override for all tests in current execution', collect, [])
|
|
161
|
-
.option('--test-config-id [test-config-id]', 'test config
|
|
161
|
+
.option('--test-config-id [test-config-id]', 'test config ID to override for all tests in current execution', collect, [])
|
|
162
162
|
.option('--params-file [params-file.json]', '')
|
|
163
163
|
.option('--params [params-json-string]', '')
|
|
164
|
-
.option('-t, --testId [test-id]', 'test
|
|
164
|
+
.option('-t, --testId [test-id]', 'test ID to run', collect, [])
|
|
165
165
|
.option('run [file-glob-pattern]', 'codeful test files to run', collect, [])
|
|
166
166
|
.option('-w, --webpackConfig [webpack-configuration]', 'webpack configuration used to build the code based project')
|
|
167
|
-
.option('--test-id [test-id]', 'test
|
|
167
|
+
.option('--test-id [test-id]', 'test ID to run', collect, [])
|
|
168
168
|
.option('-l, --label [label]', 'labels to search test by', collect, [])
|
|
169
169
|
.option('-n, --name [test-name]', 'test name to run', collect, [])
|
|
170
|
-
.option('--project [project-id]', 'project
|
|
170
|
+
.option('--project [project-id]', 'project ID')
|
|
171
171
|
.option('-r, --report-file [report junit xml path]', 'where to save junit xml results file')
|
|
172
172
|
.option('--override-report-file-classname [override-report-file-classname]', 'custom junit class name for the junit reporter')
|
|
173
173
|
.option('--reporters [names]', 'report types', list)
|
|
@@ -178,7 +178,7 @@ program
|
|
|
178
178
|
.option('--protocol [grid-protocol]', 'grid protocol http or https')
|
|
179
179
|
.option('--grid-username [grid-username]', 'grid http basic auth username')
|
|
180
180
|
.option('--grid-password [grid-password]', 'grid http basic auth password')
|
|
181
|
-
.option('-gi --grid-id [grid-id]', 'grid
|
|
181
|
+
.option('-gi --grid-id [grid-id]', 'grid ID')
|
|
182
182
|
.option('-b, --browser [browser-type]', 'browser type (chrome/firefox)')
|
|
183
183
|
.option('-h, --headless [headless]', 'run in headless mode')
|
|
184
184
|
.option('-m, --mode [runner-mode]', 'use extension or selenium mode (extension/selenium/appium)')
|
|
@@ -191,7 +191,7 @@ program
|
|
|
191
191
|
.option('--test-plan [test-plan-name]', 'test plan to run', collect, [])
|
|
192
192
|
.option('--test-plan-id [test-plan-id]', 'test plan to run', collect, [])
|
|
193
193
|
.option('--suite [suite-name]', 'suite to run', collect, [])
|
|
194
|
-
.option('--suite-id [suite-id]', 'suite
|
|
194
|
+
.option('--suite-id [suite-id]', 'suite ID to run', collect, [])
|
|
195
195
|
.option('--rerun-failed-by-run-id [run-id]', 'allows re-running failed tests from a specific run ID')
|
|
196
196
|
.option('--disable-grid-check [boolean]', 'disable checking if selenium grid is available', false)
|
|
197
197
|
.option('--disable-native-events [boolean]', 'pass nativeEvents=false capability to the selenium browser (in selenium mode)', false)
|
|
@@ -203,7 +203,7 @@ program
|
|
|
203
203
|
.option('-oen --override-execution-name [execution-name]', 'override the default execution name', '')
|
|
204
204
|
.option('--retries [max_num_of_retries]', 'number of retires failure test defaults to not retrying', 0)
|
|
205
205
|
.option('--set-retention [retention-in-days]', 'set the number of days for results retention')
|
|
206
|
-
.option('--user [user-id]', 'user
|
|
206
|
+
.option('--user [user-id]', 'user ID for local Testim-CLI')
|
|
207
207
|
.option('--pass-zero-tests', 'don\'t fail the run if no tests were found')
|
|
208
208
|
|
|
209
209
|
.option('-str --suppress-tms-reporting [suppress-tms-reporting]', 'disable test management reporting', false)
|
|
@@ -301,7 +301,7 @@ program
|
|
|
301
301
|
.option('--tunnel-region [tunnel-region]', 'ngrok tunnel region')
|
|
302
302
|
.option('--tunnel-diagnostics', 'collect ngrok tunnel diagnostics')
|
|
303
303
|
.option('--tunnel-use-http-address [tunnel-use-http-address]', 'use http:// address instead of https://', false)
|
|
304
|
-
.option('--external-lambdatest-tunnel-id [tunnel-id]', 'use existing lambdatest tunnel
|
|
304
|
+
.option('--external-lambdatest-tunnel-id [tunnel-id]', 'use existing lambdatest tunnel ID')
|
|
305
305
|
.option('--external-lambdatest-use-wss', 'use wss instead of ssh for LT', false)
|
|
306
306
|
.option('--external-lambdatest-disable-automation-tunneling', 'don\'t tunnel Testim calls in LT tunnel', true)
|
|
307
307
|
|
|
@@ -337,13 +337,18 @@ program
|
|
|
337
337
|
.option('--high-speed', 'DEPRECATED: use --turbo-mode instead') // When removing, remove from the program.help output filter
|
|
338
338
|
.option('--turbo-mode', 'run in turbo mode')
|
|
339
339
|
.option('--lightweight-mode [settings]', 'run lightweight mode')
|
|
340
|
-
.option('--create-prefeched-data [location]', '
|
|
341
|
-
.option('--use-prefeched-data [location]', 'use
|
|
340
|
+
.option('--create-prefeched-data [location]', 'prefetch data into local cache file')
|
|
341
|
+
.option('--use-prefeched-data [location]', 'use prefetched data from local cache file, and force using only cached data')
|
|
342
342
|
.option('--save-rca-locally [path]', 'save root cause analysis assets locally')
|
|
343
343
|
|
|
344
344
|
.option('--exit-code-ignore-failing-tests', 'dont return non zero exit code when tests fail. non zero exit code will mean a real error occurred')
|
|
345
|
+
|
|
346
|
+
.option('--intersect-with-label [label]', 'Out of the execution\'s test list, run only those tests that have the specified label', collect, [])
|
|
347
|
+
.option('--intersect-with-suite [suiteName]', 'Out of the execution\'s test list, run only those tests that are included in the specified suite (by suite name)', collect, [])
|
|
348
|
+
.option('--intersect-with-suite-id [suiteId]', 'Out of the execution\'s test list, run only those tests that are included in the specified suite (by suite ID)', collect, [])
|
|
345
349
|
.parse(process.argv);
|
|
346
350
|
|
|
351
|
+
|
|
347
352
|
module.exports = {
|
|
348
353
|
async process() {
|
|
349
354
|
if (program.inspect) {
|
|
@@ -1179,6 +1184,13 @@ module.exports = {
|
|
|
1179
1184
|
exitCodeIgnoreFailingTests: program.exitCodeIgnoreFailingTests,
|
|
1180
1185
|
|
|
1181
1186
|
disableSockets: program.disableSockets,
|
|
1187
|
+
|
|
1188
|
+
// intersections
|
|
1189
|
+
intersections: {
|
|
1190
|
+
labels: program.intersectWithLabel.length ? [program.intersectWithLabel].flat() : undefined,
|
|
1191
|
+
suiteNames: program.intersectWithSuite.length ? [program.intersectWithSuite].flat() : undefined,
|
|
1192
|
+
suiteIds: program.intersectWithSuiteId.length ? [program.intersectWithSuiteId].flat() : undefined,
|
|
1193
|
+
},
|
|
1182
1194
|
});
|
|
1183
1195
|
},
|
|
1184
1196
|
};
|
package/runner.js
CHANGED
|
@@ -223,7 +223,7 @@ function runRunner(options, customExtensionLocalLocation) {
|
|
|
223
223
|
}
|
|
224
224
|
|
|
225
225
|
function showFreeGridRunWarningIfNeeded(options) {
|
|
226
|
-
if (featureAvailabilityService.shouldShowFreeGridRunWarning(options.gridData.type)) {
|
|
226
|
+
if (featureAvailabilityService.shouldShowFreeGridRunWarning(options.gridData && options.gridData.type)) {
|
|
227
227
|
const CYAN = '\x1b[36m';
|
|
228
228
|
const UNDERSCORE = '\x1b[4m';
|
|
229
229
|
const RESET = '\x1b[0m';
|
|
@@ -11,6 +11,7 @@ const testimServicesApi = require('../commons/testimServicesApi');
|
|
|
11
11
|
const testimCustomToken = require('../commons/testimCustomToken');
|
|
12
12
|
const TestRunStatus = require('../testRunStatus');
|
|
13
13
|
const analyticsService = require('../services/analyticsService');
|
|
14
|
+
const gridService = require('../services/gridService');
|
|
14
15
|
const branchService = require('../services/branchService');
|
|
15
16
|
const config = require('../commons/config');
|
|
16
17
|
const ParallelWorkerManager = require('./ParallelWorkerManager');
|
|
@@ -230,7 +231,7 @@ class TestPlanRunner {
|
|
|
230
231
|
const testPlansTests = {};
|
|
231
232
|
const projectId = options.project;
|
|
232
233
|
|
|
233
|
-
const data = await testimServicesApi.getTestPlanTestList(projectId, options.testPlan, options.testPlanIds, branchToUse);
|
|
234
|
+
const data = await testimServicesApi.getTestPlanTestList(projectId, options.testPlan, options.testPlanIds, branchToUse, options.intersections);
|
|
234
235
|
const testPlans = data.testPlans;
|
|
235
236
|
const testPlansData = data.testPlansData;
|
|
236
237
|
if (!testPlans || testPlans.length === 0) {
|
|
@@ -258,6 +259,9 @@ class TestPlanRunner {
|
|
|
258
259
|
delete tpOptions.gridId;
|
|
259
260
|
}
|
|
260
261
|
|
|
262
|
+
|
|
263
|
+
tpOptions.gridData = await gridService.getTestPlanGridData(options, testPlan);
|
|
264
|
+
|
|
261
265
|
const testPlanName = tpOptions.overrideExecutionName || testPlan.name;
|
|
262
266
|
return await Promise.all(testPlansData[id].map(async testPlanTests => {
|
|
263
267
|
const res = await this.runTestPlan(testPlanTests.beforeTests, testPlanTests.tests, testPlanTests.afterTests, tpOptions, testPlanName, id, branchToUse);
|
package/runners/runnerUtils.js
CHANGED
package/services/gridService.js
CHANGED
|
@@ -235,16 +235,27 @@ function getOptionGrid(options) {
|
|
|
235
235
|
return Promise.resolve({ host, port, path, protocol, type, user, key });
|
|
236
236
|
}
|
|
237
237
|
|
|
238
|
-
async function getTestPlanGridData(options) {
|
|
239
|
-
const
|
|
240
|
-
|
|
241
|
-
|
|
242
|
-
}
|
|
243
|
-
|
|
244
|
-
|
|
245
|
-
|
|
238
|
+
async function getTestPlanGridData(options, testPlanData) {
|
|
239
|
+
const companyId = options.company.companyId;
|
|
240
|
+
try {
|
|
241
|
+
return await getGridDataByGridId(companyId, testPlanData.gridId, options.allGrids);
|
|
242
|
+
} catch (err) {
|
|
243
|
+
if (err instanceof ArgError) {
|
|
244
|
+
// this is a fallback to an old behavior that is wrong,
|
|
245
|
+
// we should remove it in the future
|
|
246
|
+
const testPlanDatas = await servicesApi.getTestPlan(options.project, options.testPlan);
|
|
247
|
+
if (testPlanDatas.length === 0) {
|
|
248
|
+
throw new ArgError(`no test plan to run ${options.testPlan}`);
|
|
249
|
+
}
|
|
250
|
+
const testPlanGrids = testPlanDatas.map(d => options.allGrids.find(grid => grid._id === d.gridId));
|
|
251
|
+
if (testPlanGrids.includes(undefined)) {
|
|
252
|
+
throw new ArgError('failed to find one of the test plan defined grid');
|
|
253
|
+
}
|
|
254
|
+
logger.warn('getTestPlanGridData used fallback and might cause test plans run on a unintended grid', { companyId });
|
|
255
|
+
return getSerializableObject(_.first(testPlanGrids));
|
|
256
|
+
}
|
|
257
|
+
throw err;
|
|
246
258
|
}
|
|
247
|
-
return getSerializableObject(_.first(testPlanGrids));
|
|
248
259
|
}
|
|
249
260
|
|
|
250
261
|
async function getGridData(options) {
|
|
@@ -253,10 +264,10 @@ async function getGridData(options) {
|
|
|
253
264
|
host, useLocalChromeDriver, useChromeLauncher, gridId, grid,
|
|
254
265
|
} = options;
|
|
255
266
|
if (useLocalChromeDriver || useChromeLauncher) {
|
|
256
|
-
return
|
|
267
|
+
return { mode: 'local' };
|
|
257
268
|
}
|
|
258
269
|
if (host) {
|
|
259
|
-
return
|
|
270
|
+
return getOptionGrid(options);
|
|
260
271
|
}
|
|
261
272
|
const companyId = company.companyId;
|
|
262
273
|
if (gridId) {
|
|
@@ -266,7 +277,8 @@ async function getGridData(options) {
|
|
|
266
277
|
return getGridDataByGridName(companyId, grid, allGrids);
|
|
267
278
|
}
|
|
268
279
|
if (hasTestPlanFlag(options)) {
|
|
269
|
-
|
|
280
|
+
logger.info('skipping getting grid, as it is set on test plan', { companyId });
|
|
281
|
+
return undefined;
|
|
270
282
|
}
|
|
271
283
|
|
|
272
284
|
throw new GridError('Missing host or grid configuration');
|
|
@@ -300,7 +312,7 @@ async function _getGridSlot(browser, executionId, testResultId, onGridSlot, opti
|
|
|
300
312
|
return gridInfo;
|
|
301
313
|
}
|
|
302
314
|
|
|
303
|
-
const handleHybridOrVendorIfNeeded = async (runnerOptions = { }, gridInfo = {}, testRunConfig = {}, lambdatestService, retryConfig = {}) => {
|
|
315
|
+
const handleHybridOrVendorIfNeeded = async (runnerOptions = { }, gridInfo = {}, testRunConfig = {}, lambdatestService = {}, retryConfig = {}) => {
|
|
304
316
|
const { company = {} } = runnerOptions;
|
|
305
317
|
const companyId = company.companyId;
|
|
306
318
|
const { gridId, type } = gridInfo;
|
|
@@ -337,6 +349,7 @@ module.exports = {
|
|
|
337
349
|
getGridSlot,
|
|
338
350
|
releaseGridSlot,
|
|
339
351
|
getGridData,
|
|
352
|
+
getTestPlanGridData,
|
|
340
353
|
addItemToGridCache,
|
|
341
354
|
keepAlive: {
|
|
342
355
|
start: startKeepAlive,
|
|
@@ -150,21 +150,14 @@ describe('gridService', () => {
|
|
|
150
150
|
.to.eventually.be.rejectedWith('Failed to find grid name: gridName');
|
|
151
151
|
});
|
|
152
152
|
|
|
153
|
-
it('should
|
|
154
|
-
const grid = await gridService.getGridData({ testPlan: 'testPlan', company: { companyId: 'companyId' }, allGrids: [{ _id: 'gridId', type: 'gridId' }] });
|
|
155
|
-
expect(grid).to.
|
|
156
|
-
sinon.assert.calledOnce(getTestPlanStub);
|
|
157
|
-
});
|
|
158
|
-
|
|
159
|
-
it('should handle grid not found error when passing test plan', async () => {
|
|
160
|
-
await expect(gridService.getGridData({ testPlan: 'testPlan', company: { companyId: 'companyId' }, allGrids: [] }))
|
|
161
|
-
.to.eventually.be.rejectedWith('failed to find one of the test plan defined grid');
|
|
153
|
+
it('should not assign a grid when using a test plan', async () => {
|
|
154
|
+
const grid = await gridService.getGridData({ testPlan: ['testPlan'], company: { companyId: 'companyId' }, allGrids: [{ _id: 'gridId', type: 'gridId' }] });
|
|
155
|
+
expect(grid).to.be.undefined;
|
|
162
156
|
});
|
|
163
157
|
|
|
164
|
-
it('should
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
.to.eventually.be.rejectedWith('no test plan to run testPlan');
|
|
158
|
+
it('should not assign a grid when using a test plan id', async () => {
|
|
159
|
+
const grid = await gridService.getGridData({ testPlanIds: ['testPlan'], company: { companyId: 'companyId' }, allGrids: [{ _id: 'gridId', type: 'gridId' }] });
|
|
160
|
+
expect(grid).to.be.undefined;
|
|
168
161
|
});
|
|
169
162
|
|
|
170
163
|
it('should throw when no grid selected', async () => {
|
package/testRunStatus.js
CHANGED
|
@@ -397,6 +397,7 @@ RunStatus.prototype.executionStart = function (executionId, projectId, startTime
|
|
|
397
397
|
remoteRunId: options.remoteRunId,
|
|
398
398
|
localRunUserId: options.user,
|
|
399
399
|
isLocalRun,
|
|
400
|
+
intersections: options.intersections,
|
|
400
401
|
};
|
|
401
402
|
const ret = servicesApi.reportExecutionStarted(data);
|
|
402
403
|
this.executionStartedPromise = ret;
|