suitest-js-api 3.7.2 → 3.8.1

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/README.md CHANGED
@@ -45,6 +45,7 @@ etc.
45
45
  - Locally installed Chrome, Firefox, Safari and Edge
46
46
  - Apple tvOS, iOS and iPadOS devices, including simulators
47
47
  - Roku
48
+ - Vizio
48
49
 
49
50
  Suitest supports automating end-to-end testing of:
50
51
 
@@ -52,11 +53,12 @@ Suitest supports automating end-to-end testing of:
52
53
  - Samsung Orsay and Tizen apps
53
54
  - LG NetCast and webOS apps
54
55
  - HTML apps for other TV's or set-top boxes
55
- - Android TV apps (including FireTV)
56
- - tvOS apps
56
+ - Android TV and mobile apps (including FireTV)
57
+ - Apple TV (tvOS), iOS and iPadOS apps
57
58
  - Xbox One and Xbox Series S and X apps
58
59
  - PlayStation 4 / 5 apps
59
60
  - Roku apps
61
+ - Vizio SmartCast
60
62
  - Traditional websites and web apps for desktop browsers.
61
63
 
62
64
  ## Contributing
package/config/index.js CHANGED
@@ -11,7 +11,7 @@ const timestamp = require('../lib/constants/timestamp');
11
11
  const {validate, validators} = require('../lib/validation');
12
12
  const {invalidConfigObj} = require('../lib/texts');
13
13
  const {pickNonNil} = require('../lib/utils/common');
14
- const envVars = require('../lib/constants/enviroment');
14
+ const envVars = require('../lib/constants/environment');
15
15
 
16
16
  const sentryDsn = 'https://1f74b885d0c44549b57f307733d60351:dd736ff3ac994104ab6635da53d9be2e@sentry.io/288812';
17
17
  const DEFAULT_TIMEOUT = 2000;
@@ -19,7 +19,7 @@ const DEFAULT_TIMEOUT = 2000;
19
19
  const overridableFields = [
20
20
  'tokenId', 'tokenPassword', 'concurrency', 'preset', 'presets', 'deviceId', 'appConfigId', 'inspect', 'inspectBrk',
21
21
  'logLevel', 'logDir', 'timestamp', 'configFile', 'disallowCrashReports', 'defaultTimeout', 'screenshotDir',
22
- 'includeChangelist',
22
+ 'includeChangelist', 'recordingOption', 'webhookUrl',
23
23
  ];
24
24
 
25
25
  const serverAddress = process.env[envVars.SUITEST_BE_SERVER] || 'the.suite.st';
package/index.d.ts CHANGED
@@ -53,10 +53,12 @@ declare namespace suitest {
53
53
  openSession(options: OpenSessionOptions): Promise<OpenSessionResult|SuitestError>;
54
54
  closeSession(): Promise<object|SuitestError>;
55
55
  setAppConfig(configId: string, options?: ConfigOverride): Promise<void|SuitestError>;
56
- pairDevice(deviceId: string): Promise<DeviceData|SuitestError>;
56
+ pairDevice(deviceId: string, {recording, webhookUrl}: {recording?: 'autostart' | 'manualstart' | 'none', webhookUrl?: string} | undefined): Promise<DeviceData|SuitestError>;
57
57
  releaseDevice(): Promise<void|SuitestError>;
58
58
  startREPL(options?: ReplOptions): Promise<void>;
59
59
  getAppConfig(): Promise<AppConfiguration|SuitestError>;
60
+ startRecording({webhookUrl}?: {webhookUrl: string}): Promise<void|SuitestError>;
61
+ stopRecording({discard}?: {discard: boolean}): Promise<void|SuitestError>;
60
62
 
61
63
  // config
62
64
  getConfig(): ConfigureOptions;
@@ -64,6 +66,8 @@ declare namespace suitest {
64
66
  setContinueOnFatalError(continueOnFatalError: ConfigureOptions['continueOnFatalError']): void;
65
67
  setDisallowCrashReports(disallowCrashReports: ConfigureOptions['disallowCrashReports']): void;
66
68
  setLogLevel(logLevel: ConfigureOptions['logLevel']): void;
69
+ setRecordingOption(recordingOption: ConfigureOptions['recordingOption']): void;
70
+ setWebhookUrl(webhookUrl: ConfigureOptions['webhookUrl']): void;
67
71
 
68
72
  // subjects
69
73
  location(): LocationChain;
@@ -277,6 +281,8 @@ declare namespace suitest {
277
281
 
278
282
  interface ConfigureOptions {
279
283
  logLevel: 'silent'|'normal'|'verbose'|'debug'|'silly';
284
+ recordingOption: 'autostart'|'manualstart'|'none';
285
+ webhookUrl: string;
280
286
  disallowCrashReports: boolean;
281
287
  continueOnFatalError: boolean;
282
288
  defaultTimeout: number;
@@ -157,6 +157,21 @@ const webSocketsFactory = (self) => {
157
157
  });
158
158
  });
159
159
  }
160
+ } else if (
161
+ path([message.messageId, 'contentType'])(requestPromises) === 'startRecording' &&
162
+ message.content.result === 'error'
163
+ ) {
164
+ // Allowing result: 'error' for startRecording command and not interrupting test flow
165
+
166
+ const messageId = message.messageId;
167
+ const res = message.content.response || message.content;
168
+ const req = requestPromises[messageId];
169
+ const contentMessage = res.error ? res.error : texts.unknownError();
170
+
171
+ logger.error(getInfoErrorMessage(contentMessage, '', res, ''));
172
+ req.resolve(res);
173
+
174
+ delete requestPromises[messageId];
160
175
  } else {
161
176
  handleResponse(message);
162
177
  }
@@ -12,6 +12,8 @@ const contentTypes = {
12
12
  testLine: 'testLine',
13
13
  takeScreenshot: 'takeScreenshot',
14
14
  getConfiguration: 'getConfiguration',
15
+ startRecording: 'startRecording',
16
+ stopRecording: 'stopRecording',
15
17
  };
16
18
 
17
19
  Object.freeze(contentTypes);
@@ -15,12 +15,20 @@ const SuitestError = require('../utils/SuitestError');
15
15
  * Pair with device
16
16
  * @param {Object} instance - main class instance
17
17
  * @param {string} deviceId - device to connect to
18
+ * @param {Object | undefined} recordingSettings - {recording, webhookUrl} object. Optional.
18
19
  * @returns {ChainablePromise.<DeviceData>}
19
20
  */
20
- async function pairDevice({webSockets, authContext, logger, pairedDeviceContext}, deviceId) {
21
+ async function pairDevice(
22
+ {webSockets, authContext, logger, pairedDeviceContext, config},
23
+ deviceId,
24
+ recordingSettings
25
+ ) {
21
26
  // validate deviceId string to be in uuid format
22
27
  validate(validators.UUID, deviceId, invalidInputMessage(pairDevice.name, 'Device id'));
23
28
 
29
+ const recordingDefault = recordingSettings ? recordingSettings.recording : 'none';
30
+ const webhookUrlDefault = recordingSettings ? recordingSettings.webhookUrl : undefined;
31
+
24
32
  const [deviceDetails] = await getDevicesDetails({authContext}, [{device: deviceId}]);
25
33
 
26
34
  if (!deviceDetails)
@@ -31,12 +39,18 @@ async function pairDevice({webSockets, authContext, logger, pairedDeviceContext}
31
39
 
32
40
  const deviceName = deviceDetails.displayName;
33
41
 
42
+ const recordingOption = config.recordingOption || recordingDefault;
43
+
44
+ const webhookUrlOption = config.webhookUrl || webhookUrlDefault;
45
+
34
46
  logger.delayed(connectingToDevice(deviceName, deviceId), 4e3);
35
47
 
36
48
  // authorize
37
49
  const authedContent = await authContext.authorizeWs({
38
50
  type: wsContentTypes.pairDevice,
39
51
  deviceId,
52
+ recording: recordingOption,
53
+ webhookUrl: webhookUrlOption,
40
54
  }, pairDevice.name);
41
55
  // make ws request
42
56
  const res = await webSockets.send(authedContent);
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Start recording command.
3
+ */
4
+
5
+ const wsContentTypes = require('../api/wsContentTypes');
6
+ const chainPromise = require('../utils/chainPromise');
7
+ const {startRecordingMessage} = require('../texts');
8
+
9
+ /**
10
+ * Start recording
11
+ * @param {SUITEST_API} instance of main class
12
+ * @returns {ChainablePromise.<void>}
13
+ */
14
+ async function startRecording({webSockets, authContext, logger}, recordingSettings) {
15
+ const webhookUrl = recordingSettings ? recordingSettings.webhookUrl : undefined;
16
+
17
+ // authorize
18
+ const authedContent = await authContext.authorizeWs(
19
+ {
20
+ type: wsContentTypes.startRecording,
21
+ webhookUrl,
22
+ },
23
+ );
24
+
25
+ // make ws request
26
+ const response = await webSockets.send(authedContent);
27
+
28
+ if (response.result === 'success') {
29
+ logger.log(startRecordingMessage());
30
+ }
31
+ }
32
+
33
+ module.exports = chainPromise(startRecording);
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Stop recording command.
3
+ */
4
+
5
+ const wsContentTypes = require('../api/wsContentTypes');
6
+ const chainPromise = require('../utils/chainPromise');
7
+ const {stopRecordingMessage} = require('../texts');
8
+
9
+ /**
10
+ * Stop recording
11
+ * @param {SUITEST_API} instance of main class
12
+ * @returns {ChainablePromise.<void>}
13
+ */
14
+ async function stopRecording({webSockets, authContext, logger}, recordingSettings) {
15
+ const discard = recordingSettings ? recordingSettings.discard : false;
16
+
17
+ // authorize
18
+ const authedContent = await authContext.authorizeWs(
19
+ {
20
+ type: wsContentTypes.stopRecording,
21
+ discard,
22
+ },
23
+ );
24
+
25
+ // make ws request
26
+ await webSockets.send(authedContent);
27
+
28
+ logger.log(stopRecordingMessage());
29
+ }
30
+
31
+ module.exports = chainPromise(stopRecording);
@@ -8,14 +8,17 @@ const {invalidInputMessage} = require('../texts');
8
8
  * Accept modal dialog, optionally sending message
9
9
  * @param {String} [message] - text to be send to modal dialog
10
10
  */
11
- const acceptModalComposer = makeModifierComposer(composers.ACCEPT_MODAL, ['acceptModal'], (_, meta, message = null) => ({
12
- ...meta,
13
- isAcceptModal: true,
14
- acceptModalMessage: validate(
15
- validators.NON_EMPTY_STRING_OR_NUll,
16
- message,
17
- invalidInputMessage('acceptModal', 'Message value'),
18
- ),
19
- }));
11
+ const acceptModalComposer = makeModifierComposer(
12
+ composers.ACCEPT_MODAL,
13
+ ['acceptModal'],
14
+ (_, meta, message = null) => ({
15
+ ...meta,
16
+ isAcceptModal: true,
17
+ acceptModalMessage: validate(
18
+ validators.NON_EMPTY_STRING_OR_NUll,
19
+ message,
20
+ invalidInputMessage('acceptModal', 'Message value'),
21
+ ),
22
+ }));
20
23
 
21
24
  module.exports = acceptModalComposer;
@@ -8,7 +8,7 @@ const cloneComposer = makeModifierComposer(
8
8
  composers.CLONE,
9
9
  ['clone'],
10
10
  (_, meta) => ({...meta}),
11
- {unregisterParent: false}
11
+ {unregisterParent: false},
12
12
  );
13
13
 
14
14
  module.exports = cloneComposer;
@@ -22,7 +22,7 @@ const matchBrightScriptComposer = makeModifierComposer(
22
22
  val: res,
23
23
  },
24
24
  };
25
- }
25
+ },
26
26
  );
27
27
 
28
28
  module.exports = matchBrightScriptComposer;
@@ -38,16 +38,19 @@ const processMatchRepoArgs = makeArgumentsProcessor(
38
38
  }),
39
39
  );
40
40
 
41
- const matchRepoComposer = makeModifierComposer(composers.MATCH_REPO, ['matchRepo', 'matchesRepo'], (_, data, ...args) => ({
42
- ...data,
43
- comparator: {
44
- type: SUBJ_COMPARATOR.MATCH,
45
- props: validation.validate(
46
- validation.validators.ELEMENT_REPO_PROPS,
47
- processMatchRepoArgs(args),
48
- invalidInputMessage('matchRepo', 'Property')
49
- ),
50
- },
51
- }));
41
+ const matchRepoComposer = makeModifierComposer(
42
+ composers.MATCH_REPO,
43
+ ['matchRepo', 'matchesRepo'],
44
+ (_, data, ...args) => ({
45
+ ...data,
46
+ comparator: {
47
+ type: SUBJ_COMPARATOR.MATCH,
48
+ props: validation.validate(
49
+ validation.validators.ELEMENT_REPO_PROPS,
50
+ processMatchRepoArgs(args),
51
+ invalidInputMessage('matchRepo', 'Property'),
52
+ ),
53
+ },
54
+ }));
52
55
 
53
56
  module.exports = matchRepoComposer;
@@ -31,7 +31,7 @@ const processRequestArgs = makeArgumentsProcessor(
31
31
  */
32
32
  ({name, val, type = PROP_COMPARATOR.EQUAL}) => getRequestMatchItem(name, val, type),
33
33
  objArg => 'name' in objArg && 'val' in objArg,
34
- getRequestMatchItem
34
+ getRequestMatchItem,
35
35
  );
36
36
 
37
37
  const requestMatchesComposer = makeModifierComposer(
@@ -47,7 +47,7 @@ const requestMatchesComposer = makeModifierComposer(
47
47
  invalidInputMessage('requestMatch', 'Header'),
48
48
  ),
49
49
  },
50
- })
50
+ }),
51
51
  );
52
52
 
53
53
  module.exports = requestMatchesComposer;
@@ -32,7 +32,7 @@ const processResponseArgs = makeArgumentsProcessor(
32
32
  */
33
33
  ({name, val, type = PROP_COMPARATOR.EQUAL}) => getResponseMatchComposers(name, val, type),
34
34
  objArg => 'name' in objArg && 'val' in objArg,
35
- getResponseMatchComposers
35
+ getResponseMatchComposers,
36
36
  );
37
37
 
38
38
  const responseMatchesComposer = makeModifierComposer(
@@ -45,10 +45,10 @@ const responseMatchesComposer = makeModifierComposer(
45
45
  props: validation.validate(
46
46
  validation.validators.RESPONSE_MATCHES,
47
47
  processResponseArgs(args),
48
- invalidInputMessage('responseMatch', 'Header')
48
+ invalidInputMessage('responseMatch', 'Header'),
49
49
  ),
50
50
  },
51
- })
51
+ }),
52
52
  );
53
53
 
54
54
  module.exports = responseMatchesComposer;
@@ -6,12 +6,21 @@ const {invalidInputMessage} = require('../texts');
6
6
  /**
7
7
  * Defines click method
8
8
  */
9
- const swipeComposer = makeModifierComposer(composers.TAP, ['swipe', 'flick'], (_, meta, direction, distance, duration) => ({
10
- ...meta,
11
- isSwipe: true,
12
- direction: validate(validators.DIRECTIONS, direction, invalidInputMessage('swipe/flick', 'direction')),
13
- distance: validate(validators.ST_VAR_OR_POSITIVE_NUMBER, distance, invalidInputMessage('swipe/flick', 'distance')),
14
- duration: validate(validators.ST_VAR_OR_POSITIVE_NUMBER, duration, invalidInputMessage('swipe/flick', 'duration')),
15
- }));
9
+ const swipeComposer = makeModifierComposer(
10
+ composers.TAP,
11
+ ['swipe', 'flick'],
12
+ (_, meta, direction, distance, duration) => ({
13
+ ...meta,
14
+ isSwipe: true,
15
+ direction: validate(validators.DIRECTIONS, direction, invalidInputMessage('swipe/flick', 'direction')),
16
+ distance: validate(
17
+ validators.ST_VAR_OR_POSITIVE_NUMBER, distance,
18
+ invalidInputMessage('swipe/flick', 'distance'),
19
+ ),
20
+ duration: validate(
21
+ validators.ST_VAR_OR_POSITIVE_NUMBER, duration,
22
+ invalidInputMessage('swipe/flick', 'duration'),
23
+ ),
24
+ }));
16
25
 
17
26
  module.exports = swipeComposer;
@@ -1,4 +1,4 @@
1
- const ENVIROMENT_VARS = Object.freeze({
1
+ const ENVIRONMENT_VARS = Object.freeze({
2
2
  /**
3
3
  * @description indicates that session is running as launcher child process, contains deviceId|configId|ipcPortNumber
4
4
  */
@@ -7,4 +7,4 @@ const ENVIROMENT_VARS = Object.freeze({
7
7
  SUITEST_BE_SERVER: 'SUITEST_BE_SERVER',
8
8
  });
9
9
 
10
- module.exports = ENVIROMENT_VARS;
10
+ module.exports = ENVIRONMENT_VARS;
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Recording options
3
+ */
4
+
5
+ const recordingOptions = {
6
+ autoStart: 'autostart',
7
+ manualStart: 'manualstart',
8
+ none: 'none',
9
+ };
10
+
11
+ Object.freeze(recordingOptions);
12
+
13
+ module.exports = recordingOptions;
@@ -1,3 +1,5 @@
1
+ /* eslint-disable key-spacing */
2
+
1
3
  const screenOrientation = {
2
4
  PORTRAIT: 'portrait',
3
5
  PORTRAIT_REVERSED: 'portraitReversed',
@@ -2,6 +2,7 @@ const {once} = require('ramda');
2
2
  const {composeConfig} = require('../composeConfig');
3
3
  const texts = require('../../texts');
4
4
  const logLevels = require('../../constants/logLevels');
5
+ const recordingOptions = require('../../constants/recordingOptions');
5
6
  const SuitestLauncher = require('../SuitestLauncher');
6
7
  const suitest = require('../../../index');
7
8
 
@@ -99,6 +100,16 @@ const builder = yargs => {
99
100
  boolean: true,
100
101
  default: false,
101
102
  global: false,
103
+ })
104
+ .option('recording-option', {
105
+ describe: texts.cliRecordingOption(),
106
+ global: false,
107
+ choices: Object.values(recordingOptions),
108
+ })
109
+ .option('webhook-url', {
110
+ describe: 'webhook url for recording option',
111
+ global: false,
112
+ type: 'string',
102
113
  });
103
114
  };
104
115
 
@@ -6,7 +6,7 @@ const chokidar = require('chokidar');
6
6
 
7
7
  const texts = require('../texts');
8
8
  const ipcClient = require('./ipc/client');
9
- const envVars = require('../constants/enviroment');
9
+ const envVars = require('../constants/environment');
10
10
  const messageId = require('../constants/ipcMessageId');
11
11
  const errorListeners = require('../utils/errorListeners');
12
12
  const {getShortFunctionBody} = require('../utils/stringUtils');
package/lib/texts.js CHANGED
@@ -212,4 +212,7 @@ ${leaves}`,
212
212
  defaultTimeout: () => 'Globally set timeout value in milliseconds. Equals to 2000 when left out.',
213
213
  cliTimestamp: () => `Logger timestamp format. Use "${timestamp.none}" to disable. [default: "${timestamp.default}"]. This string is processed with momentJS.`,
214
214
  cliConfig: () => 'Config file to override default config.',
215
+ cliRecordingOption: () => 'Enables recording of test session',
216
+ startRecordingMessage: () => 'Recording started',
217
+ stopRecordingMessage: () => 'Recording stopped',
215
218
  };
@@ -38,6 +38,7 @@ const tokenAllowed = {
38
38
  wsContentTypes.selectConfiguration, wsContentTypes.query,
39
39
  wsContentTypes.eval, wsContentTypes.testLine,
40
40
  wsContentTypes.takeScreenshot, wsContentTypes.getConfiguration,
41
+ wsContentTypes.startRecording, wsContentTypes.stopRecording,
41
42
  ],
42
43
  };
43
44
 
@@ -56,7 +57,7 @@ const allowedRequests = {
56
57
  * Decorate http requestObject with current context headers
57
58
  * @param {*} requestObject
58
59
  * @param {*} headers
59
- * @returns requestObject decoerated with auth headers
60
+ * @returns requestObject decorated with auth headers
60
61
  */
61
62
  function decorateRequestObject(requestObject, headers) {
62
63
  return Object.assign({}, requestObject, {headers});
@@ -2,7 +2,7 @@ const {TOKEN} = require('../constants/modes');
2
2
  const chainPromise = require('./chainPromise');
3
3
  const {validate, validators} = require('../validation');
4
4
  const {captureException} = require('./sentry/Raven');
5
- const envVars = require('../constants/enviroment');
5
+ const envVars = require('../constants/environment');
6
6
  const messageId = require('../constants/ipcMessageId');
7
7
  const ipcClient = require('../testLauncher/ipc/client');
8
8
  const {replWarn} = require('../texts');
@@ -56,7 +56,11 @@ const bootstrapSession = async(suitest, {deviceId, configId, presetName}) => {
56
56
  : {};
57
57
 
58
58
  await setAppConfig(suitest, configId, configOverride);
59
- await pairDevice(suitest, deviceId);
59
+ await pairDevice(
60
+ suitest,
61
+ deviceId,
62
+ {recording: suitest.config.recording, webhookUrl: suitest.config.webhookUrl},
63
+ );
60
64
 
61
65
  if (suitest.config.isDebugMode) {
62
66
  await suitest.webSockets.send({type: wsContentTypes.enableDebugMode});
@@ -11,7 +11,7 @@ const texts = require('../texts');
11
11
 
12
12
  const Queue = require('./Queue');
13
13
  const {registerProcess} = require('../testLauncher/processReaper');
14
- const envVars = require('../constants/enviroment');
14
+ const envVars = require('../constants/environment');
15
15
 
16
16
  const {version} = require('../../package.json');
17
17
  const {stripAnsiChars} = require('./stringUtils');
@@ -192,7 +192,7 @@ function logOutput(child, chunk, logStream) {
192
192
  * needs to be called to enable sending terminal codes.
193
193
  * When repl ends the node process for some reason does not want to take over
194
194
  * the ownership of the terminal anymore (setRawMode(false) does not help).
195
- * This function manually enables ctrl+c togther with the keypress module
195
+ * This function manually enables ctrl+c together with the keypress module
196
196
  * @param {string} ch
197
197
  * @param {Object} key
198
198
  */
@@ -147,7 +147,7 @@ const deviation = {
147
147
  'then': {'type': ['number', 'string']},
148
148
  'else': {'const': 'undefined'},
149
149
  };
150
- const propComarator = {
150
+ const propComparator = {
151
151
  'type': 'string',
152
152
  'enum': Object.values(PROP_COMPARATOR),
153
153
  };
@@ -164,7 +164,7 @@ schemas[validationKeys.ELEMENT_PROPS] = {
164
164
  'type': 'string',
165
165
  'enum': Object.values(ELEMENT_PROP),
166
166
  },
167
- 'type': propComarator,
167
+ 'type': propComparator,
168
168
  'val': {'const': VALUE.REPO},
169
169
  deviation,
170
170
  }},
@@ -173,7 +173,7 @@ schemas[validationKeys.ELEMENT_PROPS] = {
173
173
  'type': 'string',
174
174
  'enum': ELEMENT_PROP_BY_TYPE.integer,
175
175
  },
176
- 'type': propComarator,
176
+ 'type': propComparator,
177
177
  'val': {'type': ['integer', 'string']},
178
178
  deviation,
179
179
  }},
@@ -182,55 +182,55 @@ schemas[validationKeys.ELEMENT_PROPS] = {
182
182
  'type': 'string',
183
183
  'enum': ELEMENT_PROP_BY_TYPE.string,
184
184
  },
185
- 'type': propComarator,
185
+ 'type': propComparator,
186
186
  'val': {'type': 'string'},
187
187
  deviation,
188
188
  }},
189
189
  {'properties': {
190
190
  'name': {'enum': ELEMENT_PROP_BY_TYPE.number},
191
- 'type': propComarator,
191
+ 'type': propComparator,
192
192
  'val': {'type': ['number', 'string']},
193
193
  deviation,
194
194
  }},
195
195
  {'properties': {
196
196
  'name': {'enum': ELEMENT_PROP_BY_TYPE.boolean},
197
- 'type': propComarator,
197
+ 'type': propComparator,
198
198
  'val': {'type': 'boolean'},
199
199
  deviation,
200
200
  }},
201
201
  {'properties': {
202
202
  'name': {'const': ELEMENT_PROP.BORDER_STYLE},
203
- 'type': propComarator,
203
+ 'type': propComparator,
204
204
  'val': {'enum': Object.values(BORDER_STYLE)},
205
205
  }},
206
206
  {'properties': {
207
207
  'name': {'const': ELEMENT_PROP.VIDEO_STATE},
208
- 'type': propComarator,
208
+ 'type': propComparator,
209
209
  'val': {'enum': Object.values(VIDEO_STATE)},
210
210
  }},
211
211
  {'properties': {
212
212
  'name': {'const': ELEMENT_PROP.VISIBILITY},
213
- 'type': propComarator,
213
+ 'type': propComparator,
214
214
  'val': {'enum': [VISIBILITY_STATE.COLLAPSED, VISIBILITY_STATE.INVISIBLE, VISIBILITY_STATE.VISIBLE]},
215
215
  }},
216
216
  {'properties': {
217
217
  'name': {'const': ELEMENT_PROP.CONTENT_MODE},
218
- 'type': propComarator,
218
+ 'type': propComparator,
219
219
  'val': {'enum': Object.values(CONTENT_MODE)},
220
220
  }},
221
221
  {'properties': {
222
222
  'name': {'const': ELEMENT_PROP.STATE},
223
- 'type': propComarator,
223
+ 'type': propComparator,
224
224
  'val': {'enum': Object.values(ELEMENT_STATE)},
225
225
  }},
226
226
  {'properties': {
227
227
  'name': {'const': ELEMENT_PROP.TEXT_ALIGNMENT},
228
- 'type': propComarator,
228
+ 'type': propComparator,
229
229
  'val': {'enum': Object.values(TEXT_ALIGNMENT)},
230
230
  }},
231
231
  {'properties': {
232
232
  'name': {'const': ELEMENT_PROP.IMAGE_LOAD_STATE},
233
- 'type': propComarator,
233
+ 'type': propComparator,
234
234
  'val': {'enum': Object.values(IMAGE_LOAD_STATE)},
235
235
  }},
236
236
  ],
@@ -245,7 +245,7 @@ schemas[validationKeys.ELEMENT_REPO_PROPS] = {
245
245
  'additionalProperties': false,
246
246
  'properties': {
247
247
  'name': {'enum': Object.values(ELEMENT_PROP)},
248
- 'type': propComarator,
248
+ 'type': propComparator,
249
249
  'val': {'const': VALUE.REPO},
250
250
  deviation,
251
251
  },
@@ -261,17 +261,17 @@ schemas[validationKeys.REQUEST_MATCHES] = {
261
261
  {'properties': {
262
262
  'name': {'type': 'string'},
263
263
  'val': {'type': 'string'},
264
- 'compare': propComarator,
264
+ 'compare': propComparator,
265
265
  }},
266
266
  {'properties': {
267
267
  'name': {'const': NETWORK_PROP.METHOD},
268
268
  'val': {'enum': Object.values(NETWORK_METHOD)},
269
- 'compare': propComarator,
269
+ 'compare': propComparator,
270
270
  }},
271
271
  {'properties': {
272
272
  'name': {'const': NETWORK_PROP.BODY},
273
273
  'val': {'type': 'string'},
274
- 'compare': propComarator,
274
+ 'compare': propComparator,
275
275
  }},
276
276
  ],
277
277
  },
@@ -286,17 +286,17 @@ schemas[validationKeys.RESPONSE_MATCHES] = {
286
286
  {'properties': {
287
287
  'name': {'type': 'string'},
288
288
  'val': {'type': 'string'},
289
- 'compare': propComarator,
289
+ 'compare': propComparator,
290
290
  }},
291
291
  {'properties': {
292
292
  'name': {'const': NETWORK_PROP.STATUS},
293
293
  'val': {'type': ['number', 'string']},
294
- 'compare': propComarator,
294
+ 'compare': propComparator,
295
295
  }},
296
296
  {'properties': {
297
297
  'name': {'const': NETWORK_PROP.BODY},
298
298
  'val': {'type': 'string'},
299
- 'compare': propComarator,
299
+ 'compare': propComparator,
300
300
  }},
301
301
  ],
302
302
  },
@@ -383,6 +383,8 @@ schemas[validationKeys.CONFIGURE] = {
383
383
  'presets': {'type': 'object'},
384
384
  'screenshotDir': {'type': 'string'},
385
385
  'includeChangelist': {'type': 'boolean'},
386
+ 'recordingOption': {'type': 'string'},
387
+ 'webhookUrl': {'type': 'string'},
386
388
  },
387
389
  };
388
390
 
@@ -28,8 +28,6 @@ function throwError(text) {
28
28
  );
29
29
  }
30
30
 
31
- const getElementPropName = (mapOfNames, name) => typeof mapOfNames[name] === 'string' ? mapOfNames[name] : name;
32
-
33
31
  /**
34
32
  * @description returns prettified errors messages for element properties errors
35
33
  * @param {Object} validate
@@ -130,7 +128,7 @@ function prettifyJsonSchemaErrors(validate) {
130
128
  * @param {*|Symbol} schemaKey json schema of schemas map key
131
129
  * @param {*} data
132
130
  * @param {String} errorMessage
133
- * @returns {*} input data or thorws error
131
+ * @returns {*} input data or throws error
134
132
  * @throws SuitestError
135
133
  */
136
134
  function validateJsonSchema(schemaKey, data, errorMessage) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "suitest-js-api",
3
- "version": "3.7.2",
3
+ "version": "3.8.1",
4
4
  "main": "index.js",
5
5
  "repository": "git@github.com:SuitestAutomation/suitest-js-api.git",
6
6
  "author": "Suitest <hello@suite.st>",
@@ -18,6 +18,7 @@
18
18
  "Android TV testing",
19
19
  "Apple TV testing",
20
20
  "Roku testing",
21
+ "Vizio SmartCast testing",
21
22
  "Smart TV test automation",
22
23
  "Fire TV test automation"
23
24
  ],
package/suitest.js CHANGED
@@ -8,6 +8,8 @@ const {pairDevice} = require('./lib/commands/pairDevice');
8
8
  const releaseDevice = require('./lib/commands/releaseDevice');
9
9
  const {setAppConfig} = require('./lib/commands/setAppConfig');
10
10
  const {getAppConfig} = require('./lib/commands/getAppConfig');
11
+ const startRecording = require('./lib/commands/startRecording');
12
+ const stopRecording = require('./lib/commands/stopRecording');
11
13
 
12
14
  // Chains
13
15
  const openAppFactory = require('./lib/chains/openAppChain');
@@ -89,6 +91,8 @@ class SUITEST_API extends EventEmitter {
89
91
  this.setContinueOnFatalError = (continueOnFatalError) => this.configuration.override({continueOnFatalError});
90
92
  this.setDisallowCrashReports = (disallowCrashReports) => this.configuration.override({disallowCrashReports});
91
93
  this.setLogLevel = (logLevel) => this.configuration.override({logLevel});
94
+ this.setRecordingOption = (recordingOption) => this.configuration.override({recordingOption});
95
+ this.setWebhookUrl = (webhookUrl) => this.configuration.override({webhookUrl});
92
96
 
93
97
  // creating methods based on instance dependencies
94
98
  this.logger = createLogger(this.configuration.config, this.pairedDeviceContext);
@@ -102,6 +106,8 @@ class SUITEST_API extends EventEmitter {
102
106
  this.closeSession = (...args) => closeSession(this, ...args);
103
107
  this.releaseDevice = (...args) => releaseDevice(this, ...args);
104
108
  this.getAppConfig = (...args) => getAppConfig(this, ...args);
109
+ this.startRecording = (...args) => startRecording(this, ...args);
110
+ this.stopRecording = (...args) => stopRecording(this, ...args);
105
111
 
106
112
  const {openApp, openAppAssert} = openAppFactory(this);
107
113
  const {closeApp, closeAppAssert} = closeAppFactory(this);