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,19 +1,14 @@
|
|
|
1
1
|
/**
|
|
2
|
-
*
|
|
2
|
+
* Set auth context for current execution.
|
|
3
3
|
*/
|
|
4
4
|
|
|
5
5
|
const sessionConstants = require('../constants/session');
|
|
6
|
-
const request = require('../api/request');
|
|
7
|
-
const endpoints = require('../api/endpoints');
|
|
8
6
|
const {validate, validators} = require('../validation');
|
|
9
7
|
const chainPromise = require('../utils/chainPromise');
|
|
10
|
-
const SuitestError = require('../utils/SuitestError');
|
|
11
8
|
const {
|
|
12
9
|
invalidInputMessage,
|
|
13
|
-
authFailed,
|
|
14
10
|
sessionOpen,
|
|
15
11
|
sessionOpened,
|
|
16
|
-
notWhitelistedIp,
|
|
17
12
|
} = require('../texts');
|
|
18
13
|
|
|
19
14
|
/**
|
|
@@ -30,64 +25,30 @@ async function authAndConnectWS(authContext, webSockets) {
|
|
|
30
25
|
}
|
|
31
26
|
|
|
32
27
|
/**
|
|
33
|
-
|
|
34
|
-
* Set interactive session context on success.
|
|
35
|
-
*
|
|
28
|
+
*@description Open ws connection with suitest server and setup auth context.
|
|
36
29
|
* @param {Object} instance main class instance
|
|
37
|
-
* @param {
|
|
38
|
-
* @param {
|
|
30
|
+
* @param {Object} authData
|
|
31
|
+
* @param {string} authData.tokenId
|
|
32
|
+
* @param {string} authData.tokenPassword
|
|
39
33
|
* @returns {Promise} response object
|
|
40
34
|
*/
|
|
41
|
-
async function openSession({authContext, webSockets, logger}, authData
|
|
42
|
-
let authedRequestObject,
|
|
43
|
-
response;
|
|
44
|
-
|
|
35
|
+
async function openSession({authContext, webSockets, logger}, authData) {
|
|
45
36
|
logger.delayed(sessionOpen(), 4000);
|
|
46
37
|
|
|
47
38
|
// validate authData json
|
|
48
39
|
validate(validators.OPEN_SESSION, authData, invalidInputMessage(openSession.name, 'Open session data'));
|
|
49
40
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
}, {type: SuitestError.AUTH_FAILED});
|
|
56
|
-
// make api request
|
|
57
|
-
response = await request(
|
|
58
|
-
endpoints.session,
|
|
59
|
-
authedRequestObject,
|
|
60
|
-
(err) => {
|
|
61
|
-
if (err.status === 403) {
|
|
62
|
-
return new SuitestError(notWhitelistedIp(), SuitestError.AUTH_FAILED);
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
return new SuitestError(authFailed(), SuitestError.AUTH_FAILED);
|
|
66
|
-
},
|
|
67
|
-
);
|
|
68
|
-
// if success, set interactive session context
|
|
69
|
-
authContext.setContext(sessionConstants.INTERACTIVE, response.deviceAccessToken);
|
|
70
|
-
|
|
71
|
-
await authAndConnectWS(authContext, webSockets);
|
|
72
|
-
} else if ('sessionToken' in authData) {
|
|
73
|
-
response = {deviceAccessToken: authData.sessionToken};
|
|
74
|
-
// if sessionToken explicitly provided, set interactive session context
|
|
75
|
-
authContext.setContext(_sessionType || sessionConstants.AUTOMATED, authData.sessionToken);
|
|
41
|
+
authContext.setContext(
|
|
42
|
+
sessionConstants.TOKEN,
|
|
43
|
+
authData.tokenId,
|
|
44
|
+
authData.tokenPassword,
|
|
45
|
+
);
|
|
76
46
|
|
|
77
|
-
|
|
78
|
-
} else {
|
|
79
|
-
response = authData;
|
|
80
|
-
// if token credentials provided, simply set access token context
|
|
81
|
-
authContext.setContext(
|
|
82
|
-
sessionConstants.ACCESS_TOKEN,
|
|
83
|
-
authData.accessTokenKey,
|
|
84
|
-
authData.accessTokenPassword
|
|
85
|
-
);
|
|
86
|
-
}
|
|
47
|
+
await authAndConnectWS(authContext, webSockets);
|
|
87
48
|
|
|
88
49
|
logger.log(sessionOpened());
|
|
89
50
|
|
|
90
|
-
return
|
|
51
|
+
return {accessToken: `${authData.tokenId}:${authData.tokenPassword}`};
|
|
91
52
|
}
|
|
92
53
|
|
|
93
54
|
module.exports = {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Pair with device command.
|
|
3
3
|
* Request control of the device.
|
|
4
|
-
* After this command is resolved,
|
|
4
|
+
* After this command is resolved, time starts to count until user calls release device method or timeout passes.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
const wsContentTypes = require('../api/wsContentTypes');
|
|
@@ -21,12 +21,12 @@ async function pairDevice({webSockets, authContext, logger, pairedDeviceContext}
|
|
|
21
21
|
// validate deviceId string to be in uuid format
|
|
22
22
|
validate(validators.UUID, deviceId, invalidInputMessage(pairDevice.name, 'Device id'));
|
|
23
23
|
|
|
24
|
-
const [deviceDetails] = await getDevicesDetails({authContext}, [deviceId]);
|
|
24
|
+
const [deviceDetails] = await getDevicesDetails({authContext}, [{device: deviceId}]);
|
|
25
25
|
|
|
26
26
|
if (!deviceDetails)
|
|
27
27
|
throw new SuitestError(
|
|
28
28
|
launcherWrongDeviceId(deviceId),
|
|
29
|
-
SuitestError.INVALID_INPUT
|
|
29
|
+
SuitestError.INVALID_INPUT,
|
|
30
30
|
);
|
|
31
31
|
|
|
32
32
|
const deviceName = deviceDetails.displayName;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Release device command.
|
|
3
3
|
* Notify server that device will no longer be needed.
|
|
4
|
-
* After this method is called
|
|
4
|
+
* After this method is called minutes stop counting.
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
const wsContentTypes = require('../api/wsContentTypes');
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Before we can "Open app" or "Open URL" user must define application config.
|
|
3
|
-
* For automated session application config already defined as part of test pack definition.
|
|
4
|
-
* For interactive session it's not defined.
|
|
5
3
|
* Furthermore, it's possible for user to open several apps sequentially, so he should be able to switch app config.
|
|
6
4
|
*/
|
|
7
5
|
const {validate, validators} = require('../validation');
|
|
@@ -8,7 +8,8 @@ const repl = require('../testLauncher/repl');
|
|
|
8
8
|
const {getShortFunctionBody} = require('../utils/stringUtils');
|
|
9
9
|
const texts = require('../texts');
|
|
10
10
|
const {stackTraceParser} = require('../utils/stackTraceParser');
|
|
11
|
-
const
|
|
11
|
+
const suitest = require('../../index');
|
|
12
|
+
const {logger} = suitest;
|
|
12
13
|
const {captureMessage} = require('../utils/sentry/Raven');
|
|
13
14
|
|
|
14
15
|
let isReplActive = false;
|
|
@@ -24,7 +25,7 @@ let replModeWasActivated = false;
|
|
|
24
25
|
* @returns {*[]}
|
|
25
26
|
*/
|
|
26
27
|
function getReplParameters(opts, suitest) {
|
|
27
|
-
// get dir where .
|
|
28
|
+
// get dir where .startREPL() was called
|
|
28
29
|
const callFile = path.normalize(stackTraceParser(new Error())[2].file);
|
|
29
30
|
const cwd = opts.cwd || path.dirname(callFile);
|
|
30
31
|
const file = path.basename(callFile);
|
|
@@ -44,12 +45,13 @@ function getReplParameters(opts, suitest) {
|
|
|
44
45
|
* @param {Function=} opts.repeater
|
|
45
46
|
* @returns {Promise} response object
|
|
46
47
|
*/
|
|
47
|
-
async function
|
|
48
|
+
async function startREPL(opts = {}) {
|
|
48
49
|
if (!replModeWasActivated) {
|
|
49
50
|
replModeWasActivated = true;
|
|
50
51
|
captureMessage('REPL mode activated');
|
|
51
52
|
}
|
|
52
53
|
|
|
54
|
+
// TODO: remove when nodejs minimum version will be increased.
|
|
53
55
|
if (semver.lt(process.version, '9.4.0')) {
|
|
54
56
|
logger.error(texts.replWrongNodeVersion(process.version));
|
|
55
57
|
process.exit(1);
|
|
@@ -58,10 +60,10 @@ async function interactive(opts = {}) {
|
|
|
58
60
|
if (isReplActive)
|
|
59
61
|
return Promise.resolve();
|
|
60
62
|
|
|
61
|
-
const {
|
|
63
|
+
const {replWarn, replWelcomeMessage, replSessionEnded} = texts;
|
|
62
64
|
|
|
63
|
-
if (!
|
|
64
|
-
logger.warn(
|
|
65
|
+
if (!suitest.config.runsOnSingleDevice) {
|
|
66
|
+
logger.warn(replWarn());
|
|
65
67
|
|
|
66
68
|
return Promise.resolve();
|
|
67
69
|
}
|
|
@@ -70,7 +72,7 @@ async function interactive(opts = {}) {
|
|
|
70
72
|
const repeater = getShortFunctionBody(opts.repeater);
|
|
71
73
|
|
|
72
74
|
logger.special(replWelcomeMessage(
|
|
73
|
-
vars, cwd, watch, repeater, logger.colors.suit
|
|
75
|
+
vars, cwd, watch, repeater, logger.colors.suit,
|
|
74
76
|
));
|
|
75
77
|
|
|
76
78
|
isReplActive = true;
|
|
@@ -88,4 +90,4 @@ async function interactive(opts = {}) {
|
|
|
88
90
|
logger.info(replSessionEnded());
|
|
89
91
|
}
|
|
90
92
|
|
|
91
|
-
module.exports =
|
|
93
|
+
module.exports = startREPL;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const {makeModifierComposer} = require('../utils/makeComposer');
|
|
2
|
+
const composers = require('../constants/composer');
|
|
3
|
+
const {validate, validators} = require('../validation');
|
|
4
|
+
const {invalidInputMessage} = require('../texts');
|
|
5
|
+
|
|
6
|
+
const attributesComposer = makeModifierComposer(
|
|
7
|
+
composers.ATTRIBUTES,
|
|
8
|
+
['getAttributes'],
|
|
9
|
+
(_, meta, attributes = []) => ({
|
|
10
|
+
...meta,
|
|
11
|
+
attributes: validate(
|
|
12
|
+
validators.ELEMENT_ATTRIBUTES,
|
|
13
|
+
attributes,
|
|
14
|
+
invalidInputMessage('getAttributes', 'Element attributes'),
|
|
15
|
+
),
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
module.exports = attributesComposer;
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
const {makeModifierComposer} = require('../utils/makeComposer');
|
|
2
|
+
const composers = require('../constants/composer');
|
|
3
|
+
const {invalidInputMessage} = require('../texts');
|
|
4
|
+
const {validate, validators} = require('../validation');
|
|
5
|
+
|
|
6
|
+
const cssPropsComposer = makeModifierComposer(
|
|
7
|
+
composers.CSS_PROPS,
|
|
8
|
+
['getCssProperties'],
|
|
9
|
+
(_, meta, cssProps) => ({
|
|
10
|
+
...meta,
|
|
11
|
+
cssProps: validate(
|
|
12
|
+
validators.CSS_PROPS,
|
|
13
|
+
cssProps,
|
|
14
|
+
invalidInputMessage('getCssProperties', 'CSS properties'),
|
|
15
|
+
),
|
|
16
|
+
}));
|
|
17
|
+
|
|
18
|
+
module.exports = cssPropsComposer;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
const {makeModifierComposer} = require('../utils/makeComposer');
|
|
2
|
+
const composers = require('../constants/composer');
|
|
3
|
+
const {validate, validators} = require('../validation');
|
|
4
|
+
const {invalidInputMessage} = require('../texts');
|
|
5
|
+
|
|
6
|
+
const handleComposer = makeModifierComposer(
|
|
7
|
+
composers.GET_HANDLE,
|
|
8
|
+
['handle'],
|
|
9
|
+
(_, meta, opts = false) => {
|
|
10
|
+
validate(
|
|
11
|
+
validators.ELEMENT_HANDLE,
|
|
12
|
+
opts,
|
|
13
|
+
invalidInputMessage('handle'),
|
|
14
|
+
);
|
|
15
|
+
const multiple = opts === true || (opts ? (typeof opts.multiple === 'boolean' ? opts.multiple : false) : false);
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
...meta,
|
|
19
|
+
handle: {multiple},
|
|
20
|
+
};
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
module.exports = handleComposer;
|
package/lib/composers/index.js
CHANGED
|
@@ -41,6 +41,9 @@ const hadNoErrorComposer = require('./hadNoErrorComposer');
|
|
|
41
41
|
const tapComposer = require('./tapComposer');
|
|
42
42
|
const scrollComposer = require('./scrollComposer');
|
|
43
43
|
const swipeComposer = require('./swipeComposer');
|
|
44
|
+
const handleComposer = require('./handleComposer');
|
|
45
|
+
const attributesComposer = require('./attributesComposer');
|
|
46
|
+
const cssPropsComposer = require('./cssPropsComposer');
|
|
44
47
|
|
|
45
48
|
module.exports = {
|
|
46
49
|
abandonComposer,
|
|
@@ -88,4 +91,7 @@ module.exports = {
|
|
|
88
91
|
tapComposer,
|
|
89
92
|
scrollComposer,
|
|
90
93
|
swipeComposer,
|
|
94
|
+
handleComposer,
|
|
95
|
+
attributesComposer,
|
|
96
|
+
cssPropsComposer,
|
|
91
97
|
};
|
|
@@ -29,12 +29,11 @@ const makeThenComposer = (getSocketMessage, callback, beforeSend) => makeMethodC
|
|
|
29
29
|
dataToTranslate = {...data};
|
|
30
30
|
delete dataToTranslate.stack;
|
|
31
31
|
} else if (data.type === 'runSnippet') {
|
|
32
|
-
const isInteractiveSession = authContext.isInteractiveSession();
|
|
33
32
|
const {appId, versionId} = appContext.context;
|
|
34
33
|
const {testId} = data;
|
|
35
34
|
|
|
36
35
|
snippets = await fetchTestDefinitions({authContext})(
|
|
37
|
-
appId, versionId, testId,
|
|
36
|
+
appId, versionId, testId, config.includeChangelist, data.stack);
|
|
38
37
|
}
|
|
39
38
|
|
|
40
39
|
if (beforeSend) {
|
|
@@ -41,6 +41,9 @@ const composers = {
|
|
|
41
41
|
REQUEST_MATCHES: Symbol('requestMatches'),
|
|
42
42
|
RESPONSE_MATCHES: Symbol('responseMatches'),
|
|
43
43
|
UNTIL: Symbol('until'),
|
|
44
|
+
GET_HANDLE: Symbol('handle'),
|
|
45
|
+
ATTRIBUTES: Symbol('getAttributes'),
|
|
46
|
+
CSS_PROPS: Symbol('getCssProp'),
|
|
44
47
|
};
|
|
45
48
|
|
|
46
49
|
Object.freeze(composers);
|
package/lib/constants/element.js
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
const ENVIROMENT_VARS = Object.freeze({
|
|
2
|
-
|
|
2
|
+
/**
|
|
3
|
+
* @description indicates that session is running as launcher child process, contains deviceId|configId|ipcPortNumber
|
|
4
|
+
*/
|
|
5
|
+
SUITEST_CHILD_PROCESS: 'SUITEST_CHILD_PROCESS',
|
|
6
|
+
SUITEST_PRESET_NAME: 'SUITEST_PRESET_NAME',
|
|
7
|
+
SUITEST_BE_SERVER: 'SUITEST_BE_SERVER',
|
|
3
8
|
});
|
|
4
9
|
|
|
5
10
|
module.exports = ENVIROMENT_VARS;
|
package/lib/constants/index.js
CHANGED
|
@@ -6,6 +6,7 @@ const constants = {
|
|
|
6
6
|
API_CONSTRUCTOR_NAME: 'SUITEST_API',
|
|
7
7
|
API_LIB_PATH_IDENTIFIERS: ['suitest-js-api/lib/', 'suitest-js-api/index.js', 'suitest-js-api/config'],
|
|
8
8
|
ASSERTION_ERROR_TYPE: 'AssertionError [ERR_ASSERTION]',
|
|
9
|
+
DEFAULT_SCREENSHOT_DIR: 'screenshots',
|
|
9
10
|
};
|
|
10
11
|
|
|
11
12
|
Object.freeze(constants);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
const messageId = Object.freeze({
|
|
2
2
|
SETUP_SESSION: 'SETUP_SESSION', // passed from launcher to child on child connect, contains config object
|
|
3
3
|
|
|
4
|
-
REPL_START: 'REPL_START', // sent from child to launcher when
|
|
4
|
+
REPL_START: 'REPL_START', // sent from child to launcher when startREPL() is called,
|
|
5
5
|
REPL_INIT: 'REPL_INIT', // launcher does some manipulations and sends REPL_INIT back
|
|
6
6
|
REPL_STOP: 'REPL_STOP', // send from child to parent when repl is closed
|
|
7
7
|
});
|
package/lib/constants/modes.js
CHANGED
package/lib/constants/session.js
CHANGED
|
@@ -5,10 +5,8 @@
|
|
|
5
5
|
*/
|
|
6
6
|
|
|
7
7
|
const sessionConstants = {
|
|
8
|
-
AUTOMATED: Symbol('sessionAutomated'),
|
|
9
|
-
INTERACTIVE: Symbol('sessionInteractive'),
|
|
10
|
-
ACCESS_TOKEN: Symbol('sessionAccessToken'),
|
|
11
8
|
GUEST: Symbol('sessionGuest'),
|
|
9
|
+
TOKEN: Symbol('sessionToken'),
|
|
12
10
|
};
|
|
13
11
|
|
|
14
12
|
Object.freeze(sessionConstants);
|
|
@@ -10,18 +10,15 @@ const validationKeys = {
|
|
|
10
10
|
ELEMENT_PROP_TYPE: Symbol('elementPropType'),
|
|
11
11
|
OPEN_SESSION: Symbol('openSession'),
|
|
12
12
|
UUID: Symbol('uuid'),
|
|
13
|
-
START_TEST_PACK: Symbol('startTestPack'),
|
|
14
13
|
SET_SCREEN_ORIENTATION: Symbol('setScreenOrientation'),
|
|
15
14
|
ELEMENT_SELECTOR: Symbol('elementSelector'),
|
|
16
15
|
ELEMENT_PROPS: Symbol('elementProps'),
|
|
17
16
|
ELEMENT_REPO_PROPS: Symbol('elementRepoProps'),
|
|
18
17
|
REQUEST_MATCHES: Symbol('requestMatches'),
|
|
19
18
|
RESPONSE_MATCHES: Symbol('responseMatches'),
|
|
20
|
-
TEST_LAUNCHER_AUTOMATED: Symbol('testLauncherAutomated'),
|
|
21
|
-
TEST_LAUNCHER_INTERACTIVE: Symbol('testLauncherInteractive'),
|
|
22
19
|
TEST_LAUNCHER_TEST_COMMAND: Symbol('testLauncherTestCommand'),
|
|
23
|
-
|
|
24
|
-
|
|
20
|
+
TEST_LAUNCHER_TOKEN: Symbol('testLauncherToken'),
|
|
21
|
+
SESSION_BOOTSTRAP_TOKEN: Symbol('autoBootstrapToken'),
|
|
25
22
|
UNTIL_CONDITION_CHAIN: Symbol('untilConditionChain'),
|
|
26
23
|
STRING: Symbol('string'),
|
|
27
24
|
HAD_NO_ERROR: Symbol('hadNoError'),
|
|
@@ -30,6 +27,9 @@ const validationKeys = {
|
|
|
30
27
|
TAP_TYPE_AND_DURATION: Symbol('tapTypeAndDuration'),
|
|
31
28
|
DIRECTIONS: Symbol('direction'),
|
|
32
29
|
LAUNCH_MODE: Symbol('launchMode'),
|
|
30
|
+
CSS_PROPS: Symbol('getCssProperties'),
|
|
31
|
+
ELEMENT_HANDLE: Symbol('handle'),
|
|
32
|
+
ELEMENT_ATTRIBUTES: Symbol('getAttributes'),
|
|
33
33
|
};
|
|
34
34
|
|
|
35
35
|
Object.freeze(validationKeys);
|
package/lib/constants/vrc.js
CHANGED
|
@@ -1,30 +1,28 @@
|
|
|
1
1
|
const {
|
|
2
|
-
finishInteractive,
|
|
3
2
|
handleLauncherError,
|
|
4
3
|
validateInput,
|
|
5
4
|
runAllDevices,
|
|
6
|
-
prepareTestPackExecution,
|
|
7
|
-
runTestOnDevice,
|
|
8
5
|
getVersion,
|
|
9
6
|
isDebugMode,
|
|
10
7
|
addLauncherIpcListeners,
|
|
11
|
-
|
|
8
|
+
throwDebugForManyDevicesError,
|
|
12
9
|
increaseMaxListeners,
|
|
13
10
|
} = require('../utils/testLauncherHelper');
|
|
14
|
-
const {
|
|
11
|
+
const {TEST_COMMAND, TOKEN} = require('../constants/modes');
|
|
12
|
+
const sessionConstants = require('../constants/session');
|
|
15
13
|
const {getDevicesDetails} = require('../utils/getDeviceInfo');
|
|
16
|
-
const {openSessionUnchained} = require('../commands/openSession');
|
|
17
14
|
const {closeSessionUnchained} = require('../commands/closeSession');
|
|
18
15
|
const {captureException} = require('../utils/sentry/Raven');
|
|
19
|
-
const
|
|
20
|
-
launcherGreeting,
|
|
21
|
-
launcherSummaryInteractive,
|
|
22
|
-
launcherWrongDeviceId,
|
|
23
|
-
} = require('../texts');
|
|
16
|
+
const t = require('../texts');
|
|
24
17
|
const {version} = require('../../package.json');
|
|
25
|
-
const SuitestError = require('../utils/SuitestError');
|
|
26
18
|
const ipcServer = require('./ipc/server');
|
|
27
19
|
const suitest = require('../../index');
|
|
20
|
+
const SuitestError = require('../utils/SuitestError');
|
|
21
|
+
|
|
22
|
+
function exitProcessWithError(message) {
|
|
23
|
+
suitest.logger.error(message);
|
|
24
|
+
process.exit(1);
|
|
25
|
+
}
|
|
28
26
|
|
|
29
27
|
class SuitestLauncher {
|
|
30
28
|
constructor(ownArgv = {}, restArgs = []) {
|
|
@@ -36,89 +34,79 @@ class SuitestLauncher {
|
|
|
36
34
|
});
|
|
37
35
|
}
|
|
38
36
|
|
|
39
|
-
async
|
|
40
|
-
suitest.logger.intro(launcherGreeting, version
|
|
41
|
-
validateInput(
|
|
37
|
+
async runTokenSession() {
|
|
38
|
+
suitest.logger.intro(t.launcherGreeting, version);
|
|
39
|
+
validateInput(TOKEN.toUpperCase(), this.ownArgv);
|
|
40
|
+
const appConfigIdAndDeviceIdPresented = this.ownArgv.appConfigId && this.ownArgv.deviceId;
|
|
41
|
+
const presetArrayDefined = this.ownArgv.preset && this.ownArgv.preset.length > 0;
|
|
42
42
|
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
// debugging not allowed in automated session
|
|
47
|
-
throwDebugInAutomatedError();
|
|
48
|
-
}
|
|
43
|
+
if (!appConfigIdAndDeviceIdPresented && !presetArrayDefined) {
|
|
44
|
+
exitProcessWithError(t['errorType.specifyRunningDevices']());
|
|
45
|
+
}
|
|
49
46
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
const
|
|
53
|
-
|
|
54
|
-
launcherVersion: version,
|
|
55
|
-
sessionToken: deviceAccessToken,
|
|
56
|
-
isDebugMode: false,
|
|
57
|
-
sessionType: AUTOMATED,
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
addLauncherIpcListeners();
|
|
61
|
-
// increase stdout max listeners based on number of child processes to avoid node warning
|
|
62
|
-
increaseMaxListeners(process.stdout, devices.length, this.ownArgv.concurrency);
|
|
47
|
+
// check that presets are exists only if appConfigId and deviceId not specified via cli
|
|
48
|
+
if (!appConfigIdAndDeviceIdPresented && presetArrayDefined) {
|
|
49
|
+
const definedPresets = Object.keys(this.ownArgv.presets || {});
|
|
50
|
+
const notFoundPresets = this.ownArgv.preset.filter(p => !definedPresets.includes(p));
|
|
63
51
|
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
this.restArgs,
|
|
67
|
-
this.ownArgv,
|
|
68
|
-
devicesWithDetails,
|
|
69
|
-
ipcPort,
|
|
70
|
-
);
|
|
71
|
-
} finally {
|
|
72
|
-
await closeSessionUnchained();
|
|
52
|
+
if (notFoundPresets.length > 0) {
|
|
53
|
+
exitProcessWithError(t['errorType.notFoundPresets'](notFoundPresets));
|
|
73
54
|
}
|
|
74
|
-
} catch (error) {
|
|
75
|
-
await captureException(error);
|
|
76
|
-
handleLauncherError(error);
|
|
77
55
|
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
async runInteractiveSession() {
|
|
81
|
-
suitest.logger.intro(launcherGreeting, version, INTERACTIVE);
|
|
82
|
-
validateInput(INTERACTIVE.toUpperCase(), this.ownArgv);
|
|
83
56
|
|
|
84
57
|
try {
|
|
85
|
-
const
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if (!deviceDetails)
|
|
94
|
-
throw new SuitestError(launcherWrongDeviceId(
|
|
95
|
-
deviceId,
|
|
96
|
-
SuitestError.INVALID_INPUT
|
|
97
|
-
));
|
|
58
|
+
const devices = appConfigIdAndDeviceIdPresented
|
|
59
|
+
? [{
|
|
60
|
+
device: this.ownArgv.deviceId,
|
|
61
|
+
config: this.ownArgv.appConfigId,
|
|
62
|
+
}]
|
|
63
|
+
: this.ownArgv.preset.map((key) => {
|
|
64
|
+
const preset = this.ownArgv.presets[key];
|
|
98
65
|
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
);
|
|
66
|
+
return {
|
|
67
|
+
device: typeof preset.device === 'string' ? preset.device : preset.device.deviceId,
|
|
68
|
+
config: typeof preset.config === 'string' ? preset.config : preset.config.configId,
|
|
69
|
+
presetName: key,
|
|
70
|
+
};
|
|
71
|
+
});
|
|
72
|
+
|
|
73
|
+
await suitest.authContext.setContext(
|
|
74
|
+
sessionConstants.TOKEN,
|
|
75
|
+
this.ownArgv.tokenId,
|
|
76
|
+
this.ownArgv.tokenPassword,
|
|
77
|
+
);
|
|
78
|
+
|
|
79
|
+
const devicesWithDetails = await getDevicesDetails(suitest, devices);
|
|
80
|
+
const runsOnSingleDevice = devicesWithDetails.length === 1;
|
|
81
|
+
|
|
82
|
+
if (devicesWithDetails.length === 0) {
|
|
83
|
+
throw new SuitestError(t['errorType.noDevices']());
|
|
84
|
+
}
|
|
105
85
|
|
|
86
|
+
// should be allowed for single device only
|
|
87
|
+
if (isDebugMode(this.ownArgv) && !runsOnSingleDevice) {
|
|
88
|
+
throwDebugForManyDevicesError();
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
try {
|
|
106
92
|
const ipcPort = await ipcServer.start({
|
|
107
93
|
...this.ownArgv,
|
|
108
94
|
launcherVersion: version,
|
|
109
|
-
sessionToken: deviceAccessToken,
|
|
110
95
|
isDebugMode: isDebugMode(this.ownArgv),
|
|
111
|
-
|
|
96
|
+
runsOnSingleDevice,
|
|
97
|
+
sessionType: TOKEN,
|
|
112
98
|
});
|
|
113
99
|
|
|
114
100
|
addLauncherIpcListeners();
|
|
101
|
+
// increase stdout max listeners based on number of child processes to avoid node warning
|
|
102
|
+
increaseMaxListeners(process.stdout, devices.length, this.ownArgv.concurrency);
|
|
115
103
|
|
|
116
|
-
|
|
117
|
-
this.restArgs,
|
|
104
|
+
await runAllDevices(
|
|
105
|
+
this.restArgs,
|
|
106
|
+
this.ownArgv,
|
|
107
|
+
devicesWithDetails,
|
|
108
|
+
ipcPort,
|
|
118
109
|
);
|
|
119
|
-
const withError = exitCode !== 0;
|
|
120
|
-
|
|
121
|
-
finishInteractive(withError);
|
|
122
110
|
} finally {
|
|
123
111
|
await closeSessionUnchained(suitest);
|
|
124
112
|
}
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
const yargs = require('yargs/yargs');
|
|
2
|
-
const
|
|
3
|
-
const interactiveCommand = require('./commands/interactive');
|
|
2
|
+
const runCommand = require('./commands/run');
|
|
4
3
|
const {version} = require('../../package.json');
|
|
5
4
|
const {stColors} = require('./launcherLogger');
|
|
6
5
|
const texts = require('../texts');
|
|
@@ -10,8 +9,7 @@ const texts = require('../texts');
|
|
|
10
9
|
*/
|
|
11
10
|
const buildYargs = () => {
|
|
12
11
|
const epilogue = texts['tl.seeMoreCommandsOptions'](
|
|
13
|
-
stColors.bold('suitest
|
|
14
|
-
stColors.bold('suitest automated --help')
|
|
12
|
+
stColors.bold('suitest run --help'),
|
|
15
13
|
);
|
|
16
14
|
|
|
17
15
|
return yargs([])
|
|
@@ -34,8 +32,7 @@ const addCommandsAndHelp = yrgs => {
|
|
|
34
32
|
.alias('help', 'h')
|
|
35
33
|
.version(version)
|
|
36
34
|
.alias('version', 'v')
|
|
37
|
-
.command(
|
|
38
|
-
.command(interactiveCommand);
|
|
35
|
+
.command(runCommand);
|
|
39
36
|
};
|
|
40
37
|
|
|
41
38
|
module.exports = {
|