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.
Files changed (64) hide show
  1. package/config/index.js +7 -7
  2. package/index.d.ts +23 -71
  3. package/lib/api/endpoints.js +0 -7
  4. package/lib/api/webSockets.js +1 -1
  5. package/lib/api/wsContentTypes.js +0 -2
  6. package/lib/chains/elementChain.js +90 -19
  7. package/lib/chains/saveScreenshotChain.js +60 -5
  8. package/lib/commands/closeSession.js +4 -29
  9. package/lib/commands/openSession.js +13 -52
  10. package/lib/commands/pairDevice.js +3 -3
  11. package/lib/commands/releaseDevice.js +1 -1
  12. package/lib/commands/setAppConfig.js +0 -2
  13. package/lib/commands/{interactive.js → startREPL.js} +10 -8
  14. package/lib/composers/attributesComposer.js +18 -0
  15. package/lib/composers/cssPropsComposer.js +18 -0
  16. package/lib/composers/handleComposer.js +23 -0
  17. package/lib/composers/index.js +6 -0
  18. package/lib/composers/thenComposer.js +1 -2
  19. package/lib/constants/composer.js +3 -0
  20. package/lib/constants/element.js +2 -0
  21. package/lib/constants/enviroment.js +6 -1
  22. package/lib/constants/index.js +1 -0
  23. package/lib/constants/ipcMessageId.js +1 -1
  24. package/lib/constants/modes.js +1 -2
  25. package/lib/constants/session.js +1 -3
  26. package/lib/constants/timestamp.js +1 -1
  27. package/lib/constants/validationKeys.js +5 -5
  28. package/lib/constants/vrc.js +2 -0
  29. package/lib/testLauncher/SuitestLauncher.js +65 -77
  30. package/lib/testLauncher/buildArgs.js +3 -6
  31. package/lib/testLauncher/commands/run.js +111 -0
  32. package/lib/testLauncher/composeConfig.js +154 -15
  33. package/lib/testLauncher/launcherLogger.js +3 -23
  34. package/lib/testLauncher/processArgs.js +1 -1
  35. package/lib/testLauncher/repl.js +3 -3
  36. package/lib/texts.js +18 -39
  37. package/lib/utils/AuthContext.js +17 -76
  38. package/lib/utils/getDeviceInfo.js +16 -10
  39. package/lib/utils/logger.js +4 -3
  40. package/lib/utils/{interactiveProgressHandler.js → progressHandler.js} +1 -1
  41. package/lib/utils/sentry/Raven.js +1 -1
  42. package/lib/utils/sessionStarter.js +43 -38
  43. package/lib/utils/socketChainHelper.js +17 -8
  44. package/lib/utils/stackTraceParser.js +25 -1
  45. package/lib/utils/testHelpers/mockHelpers.js +0 -2
  46. package/lib/utils/testHelpers/mockWebSocket.js +1 -1
  47. package/lib/utils/testHelpers/testLauncherTest.js +0 -43
  48. package/lib/utils/testLauncherHelper.js +38 -105
  49. package/lib/validation/elementPropTypes.js +2 -0
  50. package/lib/validation/jsonSchemas.js +97 -97
  51. package/lib/validation/validators.js +25 -3
  52. package/lib/validation/validatorsMap.js +13 -13
  53. package/package.json +7 -5
  54. package/suitest.js +7 -15
  55. package/typeDefinition/ElementChain.d.ts +29 -1
  56. package/typeDefinition/constants/Element.d.ts +2 -0
  57. package/typeDefinition/constants/Vrc.d.ts +2 -0
  58. package/typeDefinition/modifiers.d.ts +13 -0
  59. package/lib/commands/endTest.js +0 -28
  60. package/lib/commands/startTest.js +0 -55
  61. package/lib/commands/startTestPack.js +0 -93
  62. package/lib/testLauncher/commands/automated.js +0 -70
  63. package/lib/testLauncher/commands/common.js +0 -43
  64. package/lib/testLauncher/commands/interactive.js +0 -70
@@ -1,19 +1,14 @@
1
1
  /**
2
- * Open session with Suitest server. Set interactive session context.
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
- * Open session with suitest server by username, password.
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 {schema} authData
38
- * @param {Symbol} _sessionType session type run, for internal use only
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, _sessionType) {
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
- if ('username' in authData) {
51
- // authorize http
52
- authedRequestObject = await authContext.authorizeHttp(endpoints.session, {
53
- method: 'POST',
54
- body: authData,
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
- await authAndConnectWS(authContext, webSockets);
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 response;
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, interactive or automated time starts to count until user calls release device method or timeout passes.
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 interactive or automated minutes stop counting.
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 {authContext, logger} = require('../../index');
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 .interactive() was called
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 interactive(opts = {}) {
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 {replWarnInteractive, replWelcomeMessage, replSessionEnded} = texts;
63
+ const {replWarn, replWelcomeMessage, replSessionEnded} = texts;
62
64
 
63
- if (!authContext.isInteractiveSession()) {
64
- logger.warn(replWarnInteractive());
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 = interactive;
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;
@@ -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, isInteractiveSession, data.stack);
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);
@@ -88,6 +88,8 @@ const ELEMENT_PROP = {
88
88
  EXTENDS: 'extends',
89
89
  UI_ELEMENT_ID: 'uiElementId',
90
90
  INDEX: 'index',
91
+ OFFSET_TOP: 'offsetTop',
92
+ OFFSET_LEFT: 'offsetLeft',
91
93
  };
92
94
 
93
95
  const VALUES = {
@@ -1,5 +1,10 @@
1
1
  const ENVIROMENT_VARS = Object.freeze({
2
- SUITEST_CHILD_PROCESS: 'SUITEST_CHILD_PROCESS', // indicates that session is running as launcher child process, contains deviceId|ipcPortNumber
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;
@@ -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 interactive() is called,
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
  });
@@ -1,6 +1,5 @@
1
1
  const modes = {
2
- AUTOMATED: 'automated',
3
- INTERACTIVE: 'interactive',
2
+ TOKEN: 'token',
4
3
  TEST_COMMAND: 'TEST_COMMAND',
5
4
  };
6
5
 
@@ -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);
@@ -3,7 +3,7 @@
3
3
  */
4
4
 
5
5
  const timestamp = {
6
- default: 'MMM D HH:mm:ss',
6
+ default: 'MMM D HH:mm:ss Z',
7
7
  none: 'none',
8
8
  };
9
9
 
@@ -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
- SESSION_BOOTSTRAP_AUTOMATED: Symbol('autoBootstrapAutomated'),
24
- SESSION_BOOTSTRAP_INTERACTIVE: Symbol('autoBootstrapInteractive'),
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);
@@ -36,6 +36,8 @@ const vrcConstants = {
36
36
  NUM_7: '7',
37
37
  NUM_8: '8',
38
38
  NUM_9: '9',
39
+ NEXT: 'NEXT',
40
+ PREVIOUS: 'PREVIOUS',
39
41
  FAST_FWD: 'FAST_FWD',
40
42
  REWIND: 'REWIND',
41
43
  STOP: 'STOP',
@@ -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
- throwDebugInAutomatedError,
8
+ throwDebugForManyDevicesError,
12
9
  increaseMaxListeners,
13
10
  } = require('../utils/testLauncherHelper');
14
- const {AUTOMATED, INTERACTIVE, TEST_COMMAND} = require('../constants/modes');
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 runAutomatedSession() {
40
- suitest.logger.intro(launcherGreeting, version, AUTOMATED);
41
- validateInput(AUTOMATED.toUpperCase(), this.ownArgv);
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
- try {
44
- /* istanbul ignore if */
45
- if (isDebugMode(this.ownArgv)) {
46
- // debugging not allowed in automated session
47
- throwDebugInAutomatedError();
48
- }
43
+ if (!appConfigIdAndDeviceIdPresented && !presetArrayDefined) {
44
+ exitProcessWithError(t['errorType.specifyRunningDevices']());
45
+ }
49
46
 
50
- const {devices, deviceAccessToken} = await prepareTestPackExecution(this.ownArgv);
51
- const devicesWithDetails = await getDevicesDetails(suitest, devices);
52
- const ipcPort = await ipcServer.start({
53
- ...this.ownArgv,
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
- try {
65
- await runAllDevices(
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 {username, password, orgId, deviceId} = this.ownArgv;
86
- const {deviceAccessToken} = await openSessionUnchained(suitest, {
87
- username,
88
- password,
89
- orgId,
90
- });
91
- const [deviceDetails] = await getDevicesDetails(suitest, [deviceId]);
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
- try {
100
- suitest.logger.intro(launcherSummaryInteractive,
101
- this.restArgs.join(' '),
102
- this.ownArgv.logDir,
103
- deviceDetails.displayName,
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
- sessionType: INTERACTIVE,
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
- const exitCode = await runTestOnDevice(
117
- this.restArgs, this.ownArgv, deviceDetails, INTERACTIVE, ipcPort
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 automatedCommand = require('./commands/automated');
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 interactive --help'),
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(automatedCommand)
38
- .command(interactiveCommand);
35
+ .command(runCommand);
39
36
  };
40
37
 
41
38
  module.exports = {