suitest-js-api 2.5.2 → 3.0.3
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/config/index.js +7 -7
- package/index.d.ts +23 -71
- package/lib/api/endpoints.js +0 -7
- package/lib/api/webSockets.js +1 -1
- package/lib/api/wsContentTypes.js +0 -2
- package/lib/chains/elementChain.js +90 -19
- package/lib/chains/saveScreenshotChain.js +60 -5
- package/lib/commands/closeSession.js +4 -29
- package/lib/commands/openSession.js +13 -52
- package/lib/commands/pairDevice.js +3 -3
- package/lib/commands/releaseDevice.js +1 -1
- package/lib/commands/setAppConfig.js +0 -2
- package/lib/commands/{interactive.js → startREPL.js} +10 -8
- package/lib/composers/attributesComposer.js +18 -0
- package/lib/composers/cssPropsComposer.js +18 -0
- package/lib/composers/handleComposer.js +23 -0
- package/lib/composers/index.js +6 -0
- package/lib/composers/thenComposer.js +1 -2
- package/lib/constants/composer.js +3 -0
- package/lib/constants/element.js +2 -0
- package/lib/constants/enviroment.js +6 -1
- package/lib/constants/index.js +1 -0
- package/lib/constants/ipcMessageId.js +1 -1
- package/lib/constants/modes.js +1 -2
- package/lib/constants/session.js +1 -3
- package/lib/constants/timestamp.js +1 -1
- package/lib/constants/validationKeys.js +5 -5
- package/lib/constants/vrc.js +2 -0
- package/lib/testLauncher/SuitestLauncher.js +65 -77
- package/lib/testLauncher/buildArgs.js +3 -6
- package/lib/testLauncher/commands/run.js +111 -0
- package/lib/testLauncher/composeConfig.js +154 -15
- package/lib/testLauncher/launcherLogger.js +3 -23
- package/lib/testLauncher/processArgs.js +1 -1
- package/lib/testLauncher/repl.js +3 -3
- package/lib/texts.js +18 -39
- package/lib/utils/AuthContext.js +17 -76
- package/lib/utils/getDeviceInfo.js +16 -10
- package/lib/utils/logger.js +4 -3
- package/lib/utils/{interactiveProgressHandler.js → progressHandler.js} +1 -1
- package/lib/utils/sentry/Raven.js +1 -1
- package/lib/utils/sessionStarter.js +43 -38
- package/lib/utils/socketChainHelper.js +17 -8
- package/lib/utils/stackTraceParser.js +25 -1
- package/lib/utils/testHelpers/mockHelpers.js +0 -2
- package/lib/utils/testHelpers/mockWebSocket.js +1 -1
- package/lib/utils/testHelpers/testLauncherTest.js +0 -43
- package/lib/utils/testLauncherHelper.js +38 -105
- package/lib/validation/elementPropTypes.js +2 -0
- package/lib/validation/jsonSchemas.js +97 -97
- package/lib/validation/validators.js +25 -3
- package/lib/validation/validatorsMap.js +13 -13
- package/package.json +7 -5
- package/suitest.js +7 -15
- package/typeDefinition/ElementChain.d.ts +29 -1
- package/typeDefinition/constants/Element.d.ts +2 -0
- package/typeDefinition/constants/Vrc.d.ts +2 -0
- package/typeDefinition/modifiers.d.ts +13 -0
- package/lib/commands/endTest.js +0 -28
- package/lib/commands/startTest.js +0 -55
- package/lib/commands/startTestPack.js +0 -93
- package/lib/testLauncher/commands/automated.js +0 -70
- package/lib/testLauncher/commands/common.js +0 -43
- package/lib/testLauncher/commands/interactive.js +0 -70
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
const read = require('read');
|
|
2
1
|
const ramda = require('ramda');
|
|
3
2
|
const path = require('path');
|
|
4
3
|
const moment = require('moment');
|
|
@@ -12,17 +11,14 @@ const texts = require('../texts');
|
|
|
12
11
|
|
|
13
12
|
const Queue = require('./Queue');
|
|
14
13
|
const {registerProcess} = require('../testLauncher/processReaper');
|
|
15
|
-
const {startTestPackUnchained} = require('../commands/startTestPack');
|
|
16
14
|
const envVars = require('../constants/enviroment');
|
|
17
15
|
|
|
18
16
|
const {version} = require('../../package.json');
|
|
19
17
|
const {stripAnsiChars} = require('./stringUtils');
|
|
20
18
|
|
|
21
|
-
const {
|
|
19
|
+
const {TEST_COMMAND} = require('../constants/modes');
|
|
22
20
|
|
|
23
21
|
const {fetchLatestSuitestVersion, warnNewVersionAvailable} = require('./packageMetadataHelper');
|
|
24
|
-
const SuitestError = require('./SuitestError');
|
|
25
|
-
const t = require('../texts');
|
|
26
22
|
|
|
27
23
|
const ipcServer = require('../testLauncher/ipc/server');
|
|
28
24
|
const messageId = require('../constants/ipcMessageId');
|
|
@@ -56,31 +52,9 @@ function handleChildResult(finishedWithErrors) {
|
|
|
56
52
|
}
|
|
57
53
|
}
|
|
58
54
|
|
|
59
|
-
/**
|
|
60
|
-
* Prompt user password.
|
|
61
|
-
* If nothing provided, ask again.
|
|
62
|
-
*/
|
|
63
|
-
function promptPassword() {
|
|
64
|
-
return new Promise((resolve) => read({
|
|
65
|
-
prompt: texts['tl.promptPassword'](),
|
|
66
|
-
silent: true,
|
|
67
|
-
replace: '*',
|
|
68
|
-
}, (err, pass) => {
|
|
69
|
-
/* istanbul ignore if */
|
|
70
|
-
if (err) {
|
|
71
|
-
// prompt dismissed with CTRL+C or the like.
|
|
72
|
-
process.stdout.write('\n');
|
|
73
|
-
} else if (!pass) {
|
|
74
|
-
resolve(promptPassword());
|
|
75
|
-
} else {
|
|
76
|
-
resolve(pass);
|
|
77
|
-
}
|
|
78
|
-
}));
|
|
79
|
-
}
|
|
80
|
-
|
|
81
55
|
/**
|
|
82
56
|
* Validate test launcher's args based on session type
|
|
83
|
-
* @param {
|
|
57
|
+
* @param {'TEST_COMMAND'|'TOKEN'} type session type
|
|
84
58
|
* @param {Object} args test launcher arguments
|
|
85
59
|
*/
|
|
86
60
|
function validateInput(type, args) {
|
|
@@ -91,7 +65,7 @@ function validateInput(type, args) {
|
|
|
91
65
|
|
|
92
66
|
validation.validate(
|
|
93
67
|
validation.validators[`TEST_LAUNCHER_${type}`],
|
|
94
|
-
args, msg
|
|
68
|
+
args, msg,
|
|
95
69
|
);
|
|
96
70
|
} catch (error) {
|
|
97
71
|
log.argsValidationError(error);
|
|
@@ -169,10 +143,10 @@ function isDebugMode({inspectBrk, inspect}) {
|
|
|
169
143
|
}
|
|
170
144
|
|
|
171
145
|
/**
|
|
172
|
-
* Throw error and exit process when user wants to run debugging
|
|
146
|
+
* Throw error and exit process when user wants to run debugging with multiply devices
|
|
173
147
|
*/
|
|
174
|
-
function
|
|
175
|
-
logger.error(texts['tl.
|
|
148
|
+
function throwDebugForManyDevicesError() {
|
|
149
|
+
logger.error(texts['tl.inspectOnlyForSingleDevice']());
|
|
176
150
|
process.exit(1);
|
|
177
151
|
}
|
|
178
152
|
|
|
@@ -181,10 +155,10 @@ function throwDebugInAutomatedError() {
|
|
|
181
155
|
* @param {Array} cmdArgv - user test command and it's parameters
|
|
182
156
|
* @param {Object} ownArgv - implicitly derived launcher parameters
|
|
183
157
|
* @param {Object} options - child process environment options
|
|
184
|
-
* @param {
|
|
158
|
+
* @param {Boolean} singleDeviceOnly - overall execution will be ran for single device
|
|
185
159
|
* @returns {ChildProcess} - spawned child process
|
|
186
160
|
*/
|
|
187
|
-
async function launchChild(cmdArgv, ownArgv, options,
|
|
161
|
+
async function launchChild(cmdArgv, ownArgv, options, singleDeviceOnly) {
|
|
188
162
|
const [command, ...args] = cmdArgv;
|
|
189
163
|
const debugOption = getDebugOption(ownArgv);
|
|
190
164
|
|
|
@@ -192,14 +166,14 @@ async function launchChild(cmdArgv, ownArgv, options, runMode) {
|
|
|
192
166
|
args.unshift(debugOption);
|
|
193
167
|
}
|
|
194
168
|
|
|
195
|
-
if (
|
|
169
|
+
if (singleDeviceOnly) {
|
|
196
170
|
options.stdio = 'pipe';
|
|
197
171
|
}
|
|
198
172
|
|
|
199
173
|
return cp.spawn(
|
|
200
174
|
command,
|
|
201
175
|
args,
|
|
202
|
-
options
|
|
176
|
+
options,
|
|
203
177
|
);
|
|
204
178
|
}
|
|
205
179
|
|
|
@@ -251,16 +225,16 @@ function addLauncherIpcListeners() {
|
|
|
251
225
|
* @param {ChildProcess} child - the child process instance running the test
|
|
252
226
|
* @param {Function} onExit - callback function to call when the process finishes
|
|
253
227
|
* @param {WritableStream} logStream - the output stream of the child process.
|
|
254
|
-
* @param {
|
|
228
|
+
* @param {Boolean} singleDeviceOnly - overall execution will be ran for single device
|
|
255
229
|
*/
|
|
256
|
-
function attachIO(child, onExit, logStream,
|
|
230
|
+
function attachIO(child, onExit, logStream, singleDeviceOnly) {
|
|
257
231
|
const [childIn, childOut, childErr] = child.stdio;
|
|
258
232
|
const logIo = chunk => logOutput(child, chunk, logStream);
|
|
259
233
|
|
|
260
234
|
registerProcess(child);
|
|
261
235
|
|
|
262
|
-
//
|
|
263
|
-
if (
|
|
236
|
+
// for single device execution pipe stdin so that console is not confused by REPL
|
|
237
|
+
if (singleDeviceOnly) {
|
|
264
238
|
keypress(process.stdin);
|
|
265
239
|
process.stdin.pipe(childIn);
|
|
266
240
|
childIn.on('data', logIo);
|
|
@@ -282,14 +256,14 @@ function attachIO(child, onExit, logStream, runMode) {
|
|
|
282
256
|
* @param {Array} cmdArgv - user test command and it's parameters
|
|
283
257
|
* @param {Object} ownArgv - implicitly derived launcher parameters
|
|
284
258
|
* @param {Object} device - full device information
|
|
285
|
-
* @param {
|
|
259
|
+
* @param {Boolean} singleDeviceOnly - overall execution will be ran for single device
|
|
286
260
|
* @param {number} ipcPort
|
|
287
261
|
* @returns {Promise<any>}
|
|
288
262
|
*/
|
|
289
|
-
async function runTestOnDevice(cmdArgv, ownArgv, device,
|
|
263
|
+
async function runTestOnDevice(cmdArgv, ownArgv, device, singleDeviceOnly, ipcPort) {
|
|
290
264
|
const {logDir} = ownArgv;
|
|
291
|
-
const options = getChildOptions(device
|
|
292
|
-
const child = await launchChild(cmdArgv, ownArgv, options,
|
|
265
|
+
const options = getChildOptions(device, ipcPort);
|
|
266
|
+
const child = await launchChild(cmdArgv, ownArgv, options, singleDeviceOnly);
|
|
293
267
|
const logStream = getDeviceLogStream(device, cmdArgv, new Date(), logDir);
|
|
294
268
|
|
|
295
269
|
return new Promise(resolve => {
|
|
@@ -297,34 +271,34 @@ async function runTestOnDevice(cmdArgv, ownArgv, device, runMode, ipcPort) {
|
|
|
297
271
|
cmdArgv.join(' '),
|
|
298
272
|
ownArgv.orgId,
|
|
299
273
|
ownArgv.appConfigId,
|
|
300
|
-
|
|
301
|
-
new Date()
|
|
274
|
+
new Date(),
|
|
302
275
|
));
|
|
303
276
|
|
|
304
277
|
const onExit = (exitCode, signal) => {
|
|
305
278
|
logStream && logStream.write(texts.fileLogCompleted(
|
|
306
|
-
exitCode, signal
|
|
279
|
+
exitCode, signal,
|
|
307
280
|
));
|
|
308
281
|
resolve(exitCode, signal);
|
|
309
282
|
};
|
|
310
283
|
|
|
311
|
-
attachIO(child, onExit, logStream,
|
|
284
|
+
attachIO(child, onExit, logStream, singleDeviceOnly);
|
|
312
285
|
});
|
|
313
286
|
}
|
|
314
287
|
|
|
315
288
|
/**
|
|
316
289
|
* Prepares environment for the child process.
|
|
317
290
|
*
|
|
318
|
-
* @param {string}
|
|
291
|
+
* @param {string} device - device object. deviceId and config should be provided.
|
|
319
292
|
* @param {number} port - ipc port
|
|
320
293
|
* @returns {{shell: true, env: Object}}
|
|
321
294
|
*/
|
|
322
|
-
function getChildOptions(
|
|
295
|
+
function getChildOptions(device, port) {
|
|
323
296
|
return {
|
|
324
297
|
shell: true,
|
|
325
298
|
env: {
|
|
326
299
|
...process.env,
|
|
327
|
-
[envVars.SUITEST_CHILD_PROCESS]: `${deviceId}|${port}`,
|
|
300
|
+
[envVars.SUITEST_CHILD_PROCESS]: `${device.deviceId}|${device.config}|${port}`,
|
|
301
|
+
[envVars.SUITEST_PRESET_NAME]: device.presetName,
|
|
328
302
|
FORCE_COLOR: true,
|
|
329
303
|
NODE_NO_READLINE: 1, // enable repl in advanced consoles
|
|
330
304
|
},
|
|
@@ -332,37 +306,7 @@ function getChildOptions(deviceId, port) {
|
|
|
332
306
|
}
|
|
333
307
|
|
|
334
308
|
/**
|
|
335
|
-
*
|
|
336
|
-
*
|
|
337
|
-
* @param {Object} ownArgv - implicitly derived launcher paratemers
|
|
338
|
-
* @returns {Promise<{devices, deviceAccessToken: *}>}
|
|
339
|
-
*/
|
|
340
|
-
async function prepareTestPackExecution(ownArgv) {
|
|
341
|
-
const {tokenKey, tokenId, tokenPassword, testPackId} = ownArgv;
|
|
342
|
-
|
|
343
|
-
const testPackInfo = await startTestPackUnchained(suitest, {
|
|
344
|
-
accessTokenKey: tokenKey || tokenId,
|
|
345
|
-
accessTokenPassword: tokenPassword,
|
|
346
|
-
testPackId,
|
|
347
|
-
});
|
|
348
|
-
|
|
349
|
-
const {pluck, path} = ramda;
|
|
350
|
-
const {deviceAccessToken} = testPackInfo;
|
|
351
|
-
const devices = pluck('deviceId', path(['testPack', 'devices'], testPackInfo));
|
|
352
|
-
const deviceCount = devices.length;
|
|
353
|
-
|
|
354
|
-
if (!deviceCount) {
|
|
355
|
-
throw new SuitestError(t['errorType.testPackNoDevices'](), SuitestError.INVALID_INPUT);
|
|
356
|
-
}
|
|
357
|
-
|
|
358
|
-
return {
|
|
359
|
-
devices,
|
|
360
|
-
deviceAccessToken,
|
|
361
|
-
};
|
|
362
|
-
}
|
|
363
|
-
|
|
364
|
-
/**
|
|
365
|
-
* Runs test pack on all devices in automated mode
|
|
309
|
+
* Runs all devices by spawning subprocesses
|
|
366
310
|
*
|
|
367
311
|
* @param {Array} cmdArgv - user command and it's arguments
|
|
368
312
|
* @param {Object} ownArgv - implicitly derived parameters
|
|
@@ -372,17 +316,20 @@ async function prepareTestPackExecution(ownArgv) {
|
|
|
372
316
|
*/
|
|
373
317
|
function runAllDevices(cmdArgv, ownArgv, devices, ipcPort) {
|
|
374
318
|
const tests = devices.map(device => () => runTestOnDevice(
|
|
375
|
-
cmdArgv,
|
|
319
|
+
cmdArgv,
|
|
320
|
+
ownArgv,
|
|
321
|
+
device,
|
|
322
|
+
devices.length === 1,
|
|
323
|
+
ipcPort,
|
|
376
324
|
));
|
|
377
325
|
|
|
378
326
|
const queue = new Queue(ownArgv.concurrency, tests);
|
|
379
327
|
|
|
380
328
|
logger.intro(
|
|
381
|
-
texts.
|
|
382
|
-
ownArgv.testPackId,
|
|
329
|
+
texts.launcherSummary,
|
|
383
330
|
cmdArgv.join(' '),
|
|
384
331
|
ownArgv.logDir,
|
|
385
|
-
...devices.map(device => device.displayName)
|
|
332
|
+
...devices.map(device => device.displayName),
|
|
386
333
|
);
|
|
387
334
|
|
|
388
335
|
return queue.start().then(result => {
|
|
@@ -391,26 +338,15 @@ function runAllDevices(cmdArgv, ownArgv, devices, ipcPort) {
|
|
|
391
338
|
const code = res.result.code || res.result;
|
|
392
339
|
|
|
393
340
|
return res.result.error || code !== 0;
|
|
394
|
-
}
|
|
341
|
+
},
|
|
395
342
|
);
|
|
396
343
|
|
|
397
|
-
log.
|
|
398
|
-
warnNewVersionAvailable(version, suitestVersion);
|
|
344
|
+
log.final(failedDevices.length, result.length - failedDevices.length);
|
|
345
|
+
warnNewVersionAvailable(logger, version, suitestVersion);
|
|
399
346
|
handleChildResult(failedDevices.length !== 0);
|
|
400
347
|
});
|
|
401
348
|
}
|
|
402
349
|
|
|
403
|
-
/**
|
|
404
|
-
* Completing steps for interactive run
|
|
405
|
-
*
|
|
406
|
-
* @param {Boolean} withError
|
|
407
|
-
*/
|
|
408
|
-
function finishInteractive(withError) {
|
|
409
|
-
log.finalInteractive(withError);
|
|
410
|
-
warnNewVersionAvailable(version, suitestVersion);
|
|
411
|
-
handleChildResult(withError);
|
|
412
|
-
}
|
|
413
|
-
|
|
414
350
|
/**
|
|
415
351
|
* Get's the version of the latest published suitest-js-api package
|
|
416
352
|
* @returns {Promise<String>}
|
|
@@ -428,7 +364,7 @@ async function getVersion() {
|
|
|
428
364
|
* @param {number} concurrency
|
|
429
365
|
* @modifies emitter
|
|
430
366
|
*/
|
|
431
|
-
function increaseMaxListeners(emitter, deviceCount, concurrency) {
|
|
367
|
+
function increaseMaxListeners(emitter, deviceCount, concurrency= 0) {
|
|
432
368
|
const threadCount = concurrency === 0 ? deviceCount : Math.min(concurrency, deviceCount);
|
|
433
369
|
|
|
434
370
|
emitter.setMaxListeners(emitter.getMaxListeners() + threadCount * 2);
|
|
@@ -437,16 +373,13 @@ function increaseMaxListeners(emitter, deviceCount, concurrency) {
|
|
|
437
373
|
module.exports = {
|
|
438
374
|
handleLauncherError,
|
|
439
375
|
handleChildResult,
|
|
440
|
-
promptPassword,
|
|
441
376
|
validateInput,
|
|
442
|
-
prepareTestPackExecution,
|
|
443
377
|
runTestOnDevice,
|
|
444
378
|
runAllDevices,
|
|
445
|
-
finishInteractive,
|
|
446
379
|
getVersion,
|
|
447
380
|
isDebugMode,
|
|
448
381
|
getDebugOption,
|
|
449
382
|
addLauncherIpcListeners,
|
|
450
|
-
|
|
383
|
+
throwDebugForManyDevicesError,
|
|
451
384
|
increaseMaxListeners,
|
|
452
385
|
};
|
|
@@ -92,6 +92,8 @@ const ELEMENT_PROP_TYPES = {
|
|
|
92
92
|
[ELEMENT_PROP.EXTENDS]: 'string',
|
|
93
93
|
[ELEMENT_PROP.UI_ELEMENT_ID]: 'string',
|
|
94
94
|
[ELEMENT_PROP.INDEX]: 'integer',
|
|
95
|
+
[ELEMENT_PROP.OFFSET_TOP]: 'number',
|
|
96
|
+
[ELEMENT_PROP.OFFSET_LEFT]: 'number',
|
|
95
97
|
};
|
|
96
98
|
|
|
97
99
|
Object.freeze(ELEMENT_PROP_TYPES);
|
|
@@ -28,7 +28,7 @@ schemas[validationKeys.CONFIG_OVERRIDE] = {
|
|
|
28
28
|
'type': 'array',
|
|
29
29
|
'items': {'type': 'string'},
|
|
30
30
|
},
|
|
31
|
-
'
|
|
31
|
+
'mapRules': {
|
|
32
32
|
'type': 'array',
|
|
33
33
|
'items': {
|
|
34
34
|
'type': 'object',
|
|
@@ -62,26 +62,6 @@ schemas[validationKeys.CONFIG_OVERRIDE] = {
|
|
|
62
62
|
},
|
|
63
63
|
};
|
|
64
64
|
|
|
65
|
-
schemas[validationKeys.START_TEST_PACK] = {
|
|
66
|
-
'type': 'object',
|
|
67
|
-
'required': ['testPackId', 'includeChangelist'],
|
|
68
|
-
'properties': {
|
|
69
|
-
'testPackId': {'type': ['number', 'string']},
|
|
70
|
-
'accessTokenKey': {'type': 'string'},
|
|
71
|
-
'accessTokenPassword': {'type': 'string'},
|
|
72
|
-
'config': schemas[validationKeys.CONFIG_OVERRIDE],
|
|
73
|
-
'includeChangelist': {'type': 'boolean'},
|
|
74
|
-
'metadata': {
|
|
75
|
-
'type': 'object',
|
|
76
|
-
'properties': {
|
|
77
|
-
'version': {'type': 'string'},
|
|
78
|
-
'hash': {'type': 'string'},
|
|
79
|
-
'link': {'type': 'string'},
|
|
80
|
-
},
|
|
81
|
-
},
|
|
82
|
-
},
|
|
83
|
-
};
|
|
84
|
-
|
|
85
65
|
schemas[validationKeys.LAUNCH_MODE] = {
|
|
86
66
|
'type': 'string',
|
|
87
67
|
'enum': Object.values(LAUNCH_MODE),
|
|
@@ -104,29 +84,11 @@ schemas[validationKeys.UUID] = {
|
|
|
104
84
|
|
|
105
85
|
schemas[validationKeys.OPEN_SESSION] = {
|
|
106
86
|
'type': 'object',
|
|
107
|
-
'
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
'password': {'type': 'string'},
|
|
113
|
-
'orgId': {'type': 'string'},
|
|
114
|
-
},
|
|
115
|
-
},
|
|
116
|
-
{
|
|
117
|
-
'required': ['sessionToken'],
|
|
118
|
-
'properties': {
|
|
119
|
-
'sessionToken': {'type': 'string'},
|
|
120
|
-
},
|
|
121
|
-
},
|
|
122
|
-
{
|
|
123
|
-
'required': ['accessTokenKey', 'accessTokenPassword'],
|
|
124
|
-
'properties': {
|
|
125
|
-
'accessTokenKey': {'type': 'string'},
|
|
126
|
-
'accessTokenPassword': {'type': 'string'},
|
|
127
|
-
},
|
|
128
|
-
},
|
|
129
|
-
],
|
|
87
|
+
'required': ['tokenId', 'tokenPassword'],
|
|
88
|
+
'properties': {
|
|
89
|
+
'tokenId': {'type': 'string'},
|
|
90
|
+
'tokenPassword': {'type': 'string'},
|
|
91
|
+
},
|
|
130
92
|
};
|
|
131
93
|
|
|
132
94
|
schemas[validationKeys.STRING] = {
|
|
@@ -148,23 +110,31 @@ schemas[validationKeys.ELEMENT_SELECTOR] = {
|
|
|
148
110
|
'xpath': {'type': 'string'},
|
|
149
111
|
'attributes': {'type': 'string'},
|
|
150
112
|
'text': {'type': 'string'},
|
|
113
|
+
'linkText': {'type': 'string'},
|
|
114
|
+
'partialLinkText': {'type': 'string'},
|
|
151
115
|
'position': {'type': 'string'},
|
|
152
116
|
'size': {'type': 'string'},
|
|
153
117
|
'color': {'type': 'string'},
|
|
154
118
|
'index': {
|
|
155
119
|
'type': 'integer',
|
|
156
120
|
'exclusiveMinimum': 0,
|
|
157
|
-
}
|
|
121
|
+
},
|
|
122
|
+
'handle': schemas[validationKeys.NON_EMPTY_STRING],
|
|
123
|
+
'active': {'type': 'boolean'},
|
|
158
124
|
},
|
|
159
125
|
'anyOf': [
|
|
160
126
|
{'required': ['css']},
|
|
161
127
|
{'required': ['xpath']},
|
|
162
128
|
{'required': ['attributes']},
|
|
163
129
|
{'required': ['text']},
|
|
130
|
+
{'required': ['linkText']},
|
|
131
|
+
{'required': ['partialLinkText']},
|
|
164
132
|
{'required': ['position']},
|
|
165
133
|
{'required': ['size']},
|
|
166
134
|
{'required': ['color']},
|
|
167
135
|
{'required': ['apiId']},
|
|
136
|
+
{'required': ['handle']},
|
|
137
|
+
{'required': ['active']},
|
|
168
138
|
],
|
|
169
139
|
};
|
|
170
140
|
|
|
@@ -328,63 +298,56 @@ schemas[validationKeys.RESPONSE_MATCHES] = {
|
|
|
328
298
|
},
|
|
329
299
|
};
|
|
330
300
|
|
|
331
|
-
schemas[validationKeys.
|
|
301
|
+
schemas[validationKeys.TEST_LAUNCHER_TOKEN] = {
|
|
332
302
|
'type': 'object',
|
|
333
|
-
'
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
303
|
+
'required': ['tokenId', 'tokenPassword'],
|
|
304
|
+
'properties': {
|
|
305
|
+
'tokenId': {'type': 'string'},
|
|
306
|
+
'tokenPassword': {'type': 'string'},
|
|
307
|
+
'presets': {
|
|
308
|
+
'type': 'object',
|
|
309
|
+
'additionalProperties': {
|
|
310
|
+
'type': 'object',
|
|
311
|
+
'properties': {
|
|
312
|
+
'device': {
|
|
313
|
+
'oneOf': [
|
|
314
|
+
{'type': 'string'},
|
|
315
|
+
{
|
|
316
|
+
'type': 'object',
|
|
317
|
+
'properties': {
|
|
318
|
+
'deviceId': {'type': 'string'},
|
|
319
|
+
},
|
|
320
|
+
'additionalProperties': false,
|
|
321
|
+
},
|
|
322
|
+
],
|
|
323
|
+
},
|
|
324
|
+
'config': {
|
|
325
|
+
'oneOf': [
|
|
326
|
+
{'type': 'string'},
|
|
327
|
+
{
|
|
328
|
+
'type': 'object',
|
|
329
|
+
'properties': {
|
|
330
|
+
'configId': {'type': 'string'},
|
|
331
|
+
},
|
|
332
|
+
'additionalProperties': false,
|
|
333
|
+
},
|
|
334
|
+
],
|
|
335
|
+
},
|
|
336
|
+
},
|
|
348
337
|
},
|
|
349
|
-
},
|
|
350
|
-
],
|
|
351
|
-
};
|
|
352
338
|
|
|
353
|
-
|
|
354
|
-
'type': 'object',
|
|
355
|
-
'required': ['username', 'password', 'orgId', 'deviceId', 'appConfigId'],
|
|
356
|
-
'properties': {
|
|
357
|
-
'username': {'type': 'string'},
|
|
358
|
-
'password': {'type': 'string'},
|
|
359
|
-
'orgId': {'type': 'string'},
|
|
339
|
+
},
|
|
360
340
|
'appConfigId': {'type': 'string'},
|
|
361
341
|
'deviceId': {'type': 'string'},
|
|
362
342
|
},
|
|
363
343
|
};
|
|
364
344
|
|
|
365
|
-
schemas[validationKeys.
|
|
366
|
-
'type': 'object',
|
|
367
|
-
'required': ['sessionToken'],
|
|
368
|
-
'properties': {
|
|
369
|
-
'sessionToken': {
|
|
370
|
-
'type': 'string',
|
|
371
|
-
'minLength': 1,
|
|
372
|
-
},
|
|
373
|
-
},
|
|
374
|
-
};
|
|
375
|
-
|
|
376
|
-
schemas[validationKeys.SESSION_BOOTSTRAP_INTERACTIVE] = {
|
|
345
|
+
schemas[validationKeys.SESSION_BOOTSTRAP_TOKEN] = {
|
|
377
346
|
'type': 'object',
|
|
378
|
-
'required': ['
|
|
347
|
+
'required': ['tokenId'],
|
|
379
348
|
'properties': {
|
|
380
|
-
'
|
|
381
|
-
|
|
382
|
-
'minLength': 1,
|
|
383
|
-
},
|
|
384
|
-
'appConfigId': {
|
|
385
|
-
'type': 'string',
|
|
386
|
-
'minLength': 1,
|
|
387
|
-
},
|
|
349
|
+
'tokenId': {'type': 'string'},
|
|
350
|
+
'tokenPassword': {'type': 'string'},
|
|
388
351
|
},
|
|
389
352
|
};
|
|
390
353
|
|
|
@@ -404,14 +367,17 @@ schemas[validationKeys.CONFIGURE] = {
|
|
|
404
367
|
'defaultTimeout': {'type': 'number'},
|
|
405
368
|
'logLevel': {'enum': ['silent', 'normal', 'verbose', 'debug', 'silly']},
|
|
406
369
|
'orgId': {'type': 'string'},
|
|
407
|
-
'password': {'type': 'string'},
|
|
408
370
|
'repl': {'type': 'boolean'},
|
|
409
371
|
'timestamp': {'type': 'string'},
|
|
410
|
-
'testPackId': {'type': ['number', 'string']},
|
|
411
|
-
'tokenKey': {'type': 'string'},
|
|
412
|
-
'tokenId': {'type': 'string'},
|
|
413
372
|
'tokenPassword': {'type': 'string'},
|
|
414
|
-
'
|
|
373
|
+
'tokenId': {'type': 'string'},
|
|
374
|
+
'preset': {
|
|
375
|
+
'type': 'array',
|
|
376
|
+
'items': {'type': 'string'},
|
|
377
|
+
},
|
|
378
|
+
'presets': {'type': 'object'},
|
|
379
|
+
'screenshotDir': {'type': 'string'},
|
|
380
|
+
'includeChangelist': {'type': 'boolean'},
|
|
415
381
|
},
|
|
416
382
|
};
|
|
417
383
|
|
|
@@ -440,6 +406,40 @@ schemas[validationKeys.DIRECTIONS] = {
|
|
|
440
406
|
'enum': [DIRECTIONS.UP, DIRECTIONS.DOWN, DIRECTIONS.LEFT, DIRECTIONS.RIGHT],
|
|
441
407
|
};
|
|
442
408
|
|
|
409
|
+
schemas[validationKeys.CSS_PROPS] = {
|
|
410
|
+
'schemaId': validationKeys.CSS_PROPS,
|
|
411
|
+
'type': 'array',
|
|
412
|
+
'minItems': 1,
|
|
413
|
+
'items': {
|
|
414
|
+
'type': 'string',
|
|
415
|
+
'minLength': 1,
|
|
416
|
+
},
|
|
417
|
+
};
|
|
418
|
+
|
|
419
|
+
schemas[validationKeys.ELEMENT_HANDLE] = {
|
|
420
|
+
'schemaId': validationKeys.ELEMENT_HANDLE,
|
|
421
|
+
'oneOf': [
|
|
422
|
+
{'type': 'boolean'},
|
|
423
|
+
{
|
|
424
|
+
'type': 'object',
|
|
425
|
+
'properties': {
|
|
426
|
+
'multiple': {
|
|
427
|
+
'type': 'boolean',
|
|
428
|
+
},
|
|
429
|
+
},
|
|
430
|
+
},
|
|
431
|
+
],
|
|
432
|
+
};
|
|
433
|
+
|
|
434
|
+
schemas[validationKeys.ELEMENT_ATTRIBUTES] = {
|
|
435
|
+
'schemaId': validationKeys.ELEMENT_ATTRIBUTES,
|
|
436
|
+
'type': 'array',
|
|
437
|
+
'items': {
|
|
438
|
+
'type': 'string',
|
|
439
|
+
'minLength': 1,
|
|
440
|
+
},
|
|
441
|
+
};
|
|
442
|
+
|
|
443
443
|
Object.freeze(schemas);
|
|
444
444
|
|
|
445
445
|
module.exports = schemas;
|
|
@@ -85,8 +85,27 @@ function prettifyJsonSchemaErrors(validate) {
|
|
|
85
85
|
if (validate.schema.schemaId === validationKeys.ELEMENT_PROPS) {
|
|
86
86
|
errors = prettifyElementPropsErrors(validate);
|
|
87
87
|
} else if (validate.schema.schemaId === validationKeys.CONFIGURE) {
|
|
88
|
-
|
|
89
|
-
|
|
88
|
+
errors = validate.errors.map(i => {
|
|
89
|
+
if (i.keyword === 'additionalProperties') {
|
|
90
|
+
// example: Invalid input provided for configuration object. It should NOT have additional properties: 'screenshotDir'
|
|
91
|
+
return `It ${i.message}: '${i.params.additionalProperty}'`;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
// example: Invalid input provided for configuration object. 'disallowCrashReports' should be boolean.
|
|
95
|
+
return `'${i.dataPath.slice(1)}' ${i.message}.`;
|
|
96
|
+
});
|
|
97
|
+
} else if (
|
|
98
|
+
[validationKeys.ELEMENT_ATTRIBUTES, validationKeys.CSS_PROPS].includes(validate.schema.schemaId)
|
|
99
|
+
) {
|
|
100
|
+
errors = validate.errors.map(i => {
|
|
101
|
+
if (!i.dataPath) {
|
|
102
|
+
return i.message;
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
// Example:
|
|
106
|
+
// Element attributes item at [1] index should be string
|
|
107
|
+
return `item at ${i.dataPath} index ${i.message}`;
|
|
108
|
+
});
|
|
90
109
|
} else if (validate.schema.schemaId === validationKeys.ELEMENT_SELECTOR) {
|
|
91
110
|
errors = prettifyElementSelectorsErrors(validate);
|
|
92
111
|
} else {
|
|
@@ -94,6 +113,9 @@ function prettifyJsonSchemaErrors(validate) {
|
|
|
94
113
|
if (err.keyword === 'enum') {
|
|
95
114
|
return `${err.message}: "${err.params.allowedValues.join('", "')}"`; // -> ...of the allowed values: "all", "currentUrl"
|
|
96
115
|
}
|
|
116
|
+
if (err.dataPath) {
|
|
117
|
+
return err.dataPath + ' ' + err.message;
|
|
118
|
+
}
|
|
97
119
|
|
|
98
120
|
return err.message;
|
|
99
121
|
});
|
|
@@ -226,7 +248,7 @@ const validateRepoProps = ({props, data, text}) => {
|
|
|
226
248
|
|
|
227
249
|
if (repoProps.length) {
|
|
228
250
|
throwError(
|
|
229
|
-
text + ' ' + (selector.video ? invalidVideoInheredProps : invalidInheredProps)(repoProps.join(', '))
|
|
251
|
+
text + ' ' + (selector.video ? invalidVideoInheredProps : invalidInheredProps)(repoProps.join(', ')),
|
|
230
252
|
);
|
|
231
253
|
}
|
|
232
254
|
|
|
@@ -35,9 +35,6 @@ const validatorsMap = {
|
|
|
35
35
|
[validationKeys.ELEMENT_SELECTOR]: (value, text) => {
|
|
36
36
|
return validators.validateJsonSchema(validationKeys.ELEMENT_SELECTOR, value, text);
|
|
37
37
|
},
|
|
38
|
-
[validationKeys.START_TEST_PACK]: (value, text) => {
|
|
39
|
-
return validators.validateJsonSchema(validationKeys.START_TEST_PACK, value, text);
|
|
40
|
-
},
|
|
41
38
|
[validationKeys.OPEN_SESSION]: (value, text) => {
|
|
42
39
|
return validators.validateJsonSchema(validationKeys.OPEN_SESSION, value, text);
|
|
43
40
|
},
|
|
@@ -66,20 +63,14 @@ const validatorsMap = {
|
|
|
66
63
|
[validationKeys.RESPONSE_MATCHES]: (value, text) => {
|
|
67
64
|
return validators.validateJsonSchema(validationKeys.RESPONSE_MATCHES, value, text);
|
|
68
65
|
},
|
|
69
|
-
[validationKeys.TEST_LAUNCHER_AUTOMATED]: (value, text) => {
|
|
70
|
-
return validators.validateJsonSchema(validationKeys.TEST_LAUNCHER_AUTOMATED, value, text);
|
|
71
|
-
},
|
|
72
|
-
[validationKeys.TEST_LAUNCHER_INTERACTIVE]: (value, text) => {
|
|
73
|
-
return validators.validateJsonSchema(validationKeys.TEST_LAUNCHER_INTERACTIVE, value, text);
|
|
74
|
-
},
|
|
75
66
|
[validationKeys.TEST_LAUNCHER_TEST_COMMAND]: (value, text) => {
|
|
76
67
|
return validators.validateNonEmptyArrayOfStrings(value, text);
|
|
77
68
|
},
|
|
78
|
-
[validationKeys.
|
|
79
|
-
return validators.validateJsonSchema(validationKeys.
|
|
69
|
+
[validationKeys.TEST_LAUNCHER_TOKEN]: (value, text) => {
|
|
70
|
+
return validators.validateJsonSchema(validationKeys.TEST_LAUNCHER_TOKEN, value, text);
|
|
80
71
|
},
|
|
81
|
-
[validationKeys.
|
|
82
|
-
return validators.validateJsonSchema(validationKeys.
|
|
72
|
+
[validationKeys.SESSION_BOOTSTRAP_TOKEN]: (value, text) => {
|
|
73
|
+
return validators.validateJsonSchema(validationKeys.SESSION_BOOTSTRAP_TOKEN, value, text);
|
|
83
74
|
},
|
|
84
75
|
[validationKeys.UNTIL_CONDITION_CHAIN]: value => {
|
|
85
76
|
return validators.validateUntilConditionChain(value);
|
|
@@ -96,6 +87,15 @@ const validatorsMap = {
|
|
|
96
87
|
[validationKeys.DIRECTIONS]: (value, text) => {
|
|
97
88
|
return validators.validateJsonSchema(validationKeys.DIRECTIONS, value, text);
|
|
98
89
|
},
|
|
90
|
+
[validationKeys.CSS_PROPS]: (value, text) => {
|
|
91
|
+
return validators.validateJsonSchema(validationKeys.CSS_PROPS, value, text);
|
|
92
|
+
},
|
|
93
|
+
[validationKeys.ELEMENT_HANDLE]: (value, text) => {
|
|
94
|
+
return validators.validateJsonSchema(validationKeys.ELEMENT_HANDLE, value, text);
|
|
95
|
+
},
|
|
96
|
+
[validationKeys.ELEMENT_ATTRIBUTES]: (value, text) => {
|
|
97
|
+
return validators.validateJsonSchema(validationKeys.ELEMENT_ATTRIBUTES, value, text);
|
|
98
|
+
},
|
|
99
99
|
};
|
|
100
100
|
|
|
101
101
|
Object.freeze(validatorsMap);
|