suitest-js-api 3.19.1 → 3.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/index.d.ts +13 -4
- package/lib/api/webSockets.js +16 -6
- package/lib/api/wsContentTypes.js +1 -0
- package/lib/chains/getLastVTScreenshotChain.js +56 -0
- package/lib/commands/startRecording.js +1 -1
- package/lib/composers/thenComposer.js +1 -1
- package/lib/constants/validationKeys.js +1 -0
- package/lib/utils/AuthContext.js +1 -0
- package/lib/utils/chainUtils.js +1 -1
- package/lib/utils/opType.js +2 -0
- package/lib/utils/socketChainHelper.js +44 -1
- package/lib/validation/jsonSchemas.js +5 -0
- package/lib/validation/validatorsMap.js +3 -0
- package/package.json +2 -2
- package/suitest.js +3 -0
- package/typeDefinition/GetLastVTScreenshotChain.d.ts +13 -0
package/index.d.ts
CHANGED
|
@@ -50,6 +50,7 @@ import {OcrColor} from './typeDefinition/constants/OcrColor';
|
|
|
50
50
|
import {ImageChain} from './typeDefinition/ImageChain';
|
|
51
51
|
import {Accuracy} from './typeDefinition/constants/Accuracy';
|
|
52
52
|
import {Lang} from './typeDefinition/constants/Langs';
|
|
53
|
+
import {GetLastVTScreenshotChain} from './typeDefinition/GetLastVTScreenshotChain';
|
|
53
54
|
|
|
54
55
|
// --------------- Suitest Interface ---------------------- //
|
|
55
56
|
|
|
@@ -66,7 +67,7 @@ declare namespace suitest {
|
|
|
66
67
|
releaseDevice(): Promise<void|SuitestError>;
|
|
67
68
|
startREPL(options?: ReplOptions): Promise<void>;
|
|
68
69
|
getAppConfig(): Promise<AppConfiguration|SuitestError>;
|
|
69
|
-
startRecording({webhookUrl}?: {webhookUrl: string}): Promise<
|
|
70
|
+
startRecording({webhookUrl}?: {webhookUrl: string}): Promise<string|SuitestError>;
|
|
70
71
|
stopRecording({discard}?: {discard: boolean}): Promise<void|SuitestError>;
|
|
71
72
|
|
|
72
73
|
// config
|
|
@@ -104,13 +105,13 @@ declare namespace suitest {
|
|
|
104
105
|
press(keys: string[], options?: { longPressMs?: string | number }): PressButtonChain;
|
|
105
106
|
sleep(milliseconds: number): SleepChain;
|
|
106
107
|
window(): WindowChain;
|
|
108
|
+
setScreenOrientation(orientation: ScreenOrientationValues): SetScreenOrientationChain;
|
|
107
109
|
/**
|
|
108
|
-
* @description return PromiseLike object with Buffer as value
|
|
110
|
+
* @description return PromiseLike object with Buffer as value which represents latest screenshot made for visual testing/assertions
|
|
109
111
|
*/
|
|
110
112
|
takeScreenshot(dataFormat?: 'raw'): TakeScreenshotChain<Buffer>;
|
|
111
|
-
setScreenOrientation(orientation: ScreenOrientationValues): SetScreenOrientationChain;
|
|
112
113
|
/**
|
|
113
|
-
* @description return PromiseLike object with base64 string as value
|
|
114
|
+
* @description return PromiseLike object with base64 string as value which represents latest screenshot made for visual testing/assertions
|
|
114
115
|
*/
|
|
115
116
|
takeScreenshot(dataFormat: 'base64'): TakeScreenshotChain<string>;
|
|
116
117
|
/**
|
|
@@ -127,6 +128,14 @@ declare namespace suitest {
|
|
|
127
128
|
* suitest.saveScreenshot('{screenshotDir}/{dateTime}-{currentFile}-l{currentLine}.png');
|
|
128
129
|
*/
|
|
129
130
|
saveScreenshot(fileName?: string): TakeScreenshotChain<void>;
|
|
131
|
+
/**
|
|
132
|
+
* @description returns a screenshot taken with a previous visual testing assertion (OCR or image assertions). Screenshot data will be provided as a Buffer.
|
|
133
|
+
*/
|
|
134
|
+
getLastVTScreenshot(dataFormat?: 'raw'): GetLastVTScreenshotChain<Buffer>;
|
|
135
|
+
/**
|
|
136
|
+
* @description returns a screenshot taken with a previous visual testing assertion (OCR or image assertions). Screenshot data will be provided as a base64 encoded string.
|
|
137
|
+
*/
|
|
138
|
+
getLastVTScreenshot(dataFormat: 'base64'): GetLastVTScreenshotChain<string>;
|
|
130
139
|
openDeepLink(deepLink?: string): OpenDeepLinkChain;
|
|
131
140
|
ocr(comparators: OcrCommonItem[]): OcrChain;
|
|
132
141
|
image(imageData: ImageData): ImageChain;
|
package/lib/api/webSockets.js
CHANGED
|
@@ -15,7 +15,7 @@ const {handleProgress} = require('../utils/progressHandler');
|
|
|
15
15
|
const {getInfoErrorMessage} = require('../utils/socketErrorMessages');
|
|
16
16
|
const {translateNotStartedReason} = require('../utils/translateResults');
|
|
17
17
|
const logLevels = require('../../lib/constants/logLevels');
|
|
18
|
-
const {createBufferFromSocketMessage} = require('../utils/socketChainHelper');
|
|
18
|
+
const {createBufferFromSocketMessage, parseBinarySocketMessage} = require('../utils/socketChainHelper');
|
|
19
19
|
|
|
20
20
|
/**
|
|
21
21
|
* @description print log message that comes from BE side with proper log level
|
|
@@ -151,12 +151,22 @@ const webSocketsFactory = (self) => {
|
|
|
151
151
|
},
|
|
152
152
|
});
|
|
153
153
|
|
|
154
|
-
// receiving Buffer for previous ws message related to takeScreenshot
|
|
155
154
|
if (bufferReceived) {
|
|
156
|
-
|
|
155
|
+
// if rawDataMessageId specified received buffer should be related to previous takeScreenshot, saveScreenshot ws message
|
|
156
|
+
if (rawDataMessageId !== null) {
|
|
157
|
+
const data = screenshotData(message, rawDataMessageId);
|
|
157
158
|
|
|
158
|
-
|
|
159
|
-
|
|
159
|
+
rawDataMessageId = null;
|
|
160
|
+
handleResponse(data);
|
|
161
|
+
}
|
|
162
|
+
// otherwise should be received binary format which contains json and binary pair for lastScreenshot ws message
|
|
163
|
+
else {
|
|
164
|
+
const [text, binaryData] = parseBinarySocketMessage(message);
|
|
165
|
+
const jsonMessage = JSON.parse(text);
|
|
166
|
+
|
|
167
|
+
jsonMessage.content.buffer = binaryData;
|
|
168
|
+
handleResponse(jsonMessage);
|
|
169
|
+
}
|
|
160
170
|
} else if (
|
|
161
171
|
path([message.messageId, 'contentType'])(requestPromises) === 'takeScreenshot' &&
|
|
162
172
|
message.content.result === 'success'
|
|
@@ -236,7 +246,7 @@ const webSocketsFactory = (self) => {
|
|
|
236
246
|
|
|
237
247
|
/* istanbul ignore else */
|
|
238
248
|
if (req) {
|
|
239
|
-
if (['query', 'testLine', 'eval', 'takeScreenshot'].includes(req.contentType)) {
|
|
249
|
+
if (['query', 'testLine', 'eval', 'takeScreenshot', 'lastScreenshot'].includes(req.contentType)) {
|
|
240
250
|
req.resolve({
|
|
241
251
|
...res,
|
|
242
252
|
contentType: req.contentType,
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
const makeChain = require('../utils/makeChain');
|
|
2
|
+
const {
|
|
3
|
+
makeToStringComposer,
|
|
4
|
+
makeThenComposer,
|
|
5
|
+
makeToJSONComposer,
|
|
6
|
+
abandonComposer,
|
|
7
|
+
} = require('../composers');
|
|
8
|
+
const t = require('../texts');
|
|
9
|
+
const {validate, validators} = require('../validation');
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* @param {import('../../index.d.ts').ISuitest} classInstance
|
|
13
|
+
*/
|
|
14
|
+
const getLastVTScreenshot = (classInstance) => {
|
|
15
|
+
const toJSON = () => ({type: 'lastScreenshot'});
|
|
16
|
+
|
|
17
|
+
const toStringComposer = makeToStringComposer(toJSON);
|
|
18
|
+
const thenComposer = makeThenComposer(toJSON);
|
|
19
|
+
const toJSONComposer = makeToJSONComposer(toJSON);
|
|
20
|
+
|
|
21
|
+
const getComposers = (data) => {
|
|
22
|
+
const output = [
|
|
23
|
+
toStringComposer,
|
|
24
|
+
thenComposer,
|
|
25
|
+
toJSONComposer,
|
|
26
|
+
];
|
|
27
|
+
|
|
28
|
+
if (!data.isAbandoned) {
|
|
29
|
+
output.push(abandonComposer);
|
|
30
|
+
}
|
|
31
|
+
|
|
32
|
+
return output;
|
|
33
|
+
};
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* @param {'raw' | 'base64'} [dataFormat]
|
|
37
|
+
* @returns {*}
|
|
38
|
+
*/
|
|
39
|
+
const getLastVTScreenshotChain = (dataFormat = 'raw') => makeChain(classInstance, getComposers, {
|
|
40
|
+
type: 'lastScreenshot',
|
|
41
|
+
dataFormat: validate(
|
|
42
|
+
validators.LAST_SCREENSHOT,
|
|
43
|
+
dataFormat,
|
|
44
|
+
t.invalidInputMessage('getLastVTScreenshot', 'Data format'),
|
|
45
|
+
),
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
return {
|
|
49
|
+
getLastVTScreenshot: getLastVTScreenshotChain,
|
|
50
|
+
// For Unit Testing
|
|
51
|
+
getComposers,
|
|
52
|
+
toJSON,
|
|
53
|
+
};
|
|
54
|
+
};
|
|
55
|
+
|
|
56
|
+
module.exports = getLastVTScreenshot;
|
|
@@ -9,7 +9,7 @@ const {startRecordingMessage} = require('../texts');
|
|
|
9
9
|
/**
|
|
10
10
|
* Start recording
|
|
11
11
|
* @param {SUITEST_API} instance of main class
|
|
12
|
-
* @returns {ChainablePromise.<
|
|
12
|
+
* @returns {ChainablePromise.<string>}
|
|
13
13
|
*/
|
|
14
14
|
async function startRecording({webSockets, authContext, logger}, recordingSettings) {
|
|
15
15
|
const webhookUrl = recordingSettings ? recordingSettings.webhookUrl : undefined;
|
|
@@ -29,7 +29,7 @@ const makeThenComposer = (getSocketMessage, callback, beforeSend) => makeMethodC
|
|
|
29
29
|
let dataToTranslate = jsonSocketMessage;
|
|
30
30
|
let snippets;
|
|
31
31
|
|
|
32
|
-
if (dataToTranslate.type === 'takeScreenshot') {
|
|
32
|
+
if (dataToTranslate.type === 'takeScreenshot' || dataToTranslate.type === 'lastScreenshot') {
|
|
33
33
|
dataToTranslate = {...data};
|
|
34
34
|
delete dataToTranslate.stack;
|
|
35
35
|
} else if (data.type === 'runSnippet') {
|
|
@@ -25,6 +25,7 @@ const validationKeys = {
|
|
|
25
25
|
STRING: Symbol('string'),
|
|
26
26
|
HAD_NO_ERROR: Symbol('hadNoError'),
|
|
27
27
|
TAKE_SCREENSHOT: Symbol('takeScreenshot'),
|
|
28
|
+
LAST_SCREENSHOT: Symbol('lastScreenshot'),
|
|
28
29
|
TAP_TYPE: Symbol('tapType'),
|
|
29
30
|
TAP_TYPE_AND_DURATION: Symbol('tapTypeAndDuration'),
|
|
30
31
|
DIRECTIONS: Symbol('direction'),
|
package/lib/utils/AuthContext.js
CHANGED
package/lib/utils/chainUtils.js
CHANGED
|
@@ -97,7 +97,7 @@ function getPureComparatorType(def) {
|
|
|
97
97
|
* @returns {Object}
|
|
98
98
|
*/
|
|
99
99
|
function processJsonMessageForToString(jsonMessage) {
|
|
100
|
-
return !['query', 'takeScreenshot'].includes(jsonMessage.type) && 'request' in jsonMessage
|
|
100
|
+
return !['query', 'takeScreenshot', 'lastScreenshot'].includes(jsonMessage.type) && 'request' in jsonMessage
|
|
101
101
|
? jsonMessage.request
|
|
102
102
|
: jsonMessage;
|
|
103
103
|
}
|
package/lib/utils/opType.js
CHANGED
|
@@ -43,6 +43,7 @@ const processServerResponse = (logger, verbosity) =>
|
|
|
43
43
|
const isTestLine = res.contentType === 'testLine';
|
|
44
44
|
const isQuery = res.contentType === 'query';
|
|
45
45
|
const isTakeScreenshot = res.contentType === 'takeScreenshot';
|
|
46
|
+
const isLastScreenshot = res.contentType === 'lastScreenshot';
|
|
46
47
|
const isAborted = res.result === 'aborted';
|
|
47
48
|
|
|
48
49
|
// warnings
|
|
@@ -146,6 +147,18 @@ const processServerResponse = (logger, verbosity) =>
|
|
|
146
147
|
throwErr(new SuitestError(message, SuitestError.EVALUATION_ERROR, responseForError));
|
|
147
148
|
}
|
|
148
149
|
|
|
150
|
+
// getting last screenshot for visual testing
|
|
151
|
+
if (isLastScreenshot && isSuccess) {
|
|
152
|
+
if (data.dataFormat === 'raw') {
|
|
153
|
+
return res.buffer;
|
|
154
|
+
} else if (data.dataFormat === 'base64') {
|
|
155
|
+
return res.buffer.toString('base64');
|
|
156
|
+
}
|
|
157
|
+
} else if (isLastScreenshot && !isSuccess) {
|
|
158
|
+
logger.error(infoMessage());
|
|
159
|
+
throwErr(new SuitestError(message, SuitestError.EVALUATION_ERROR, responseForError));
|
|
160
|
+
}
|
|
161
|
+
|
|
149
162
|
logger.error(infoMessage(''));
|
|
150
163
|
throwErr(new SuitestError(message, SuitestError.UNKNOWN_ERROR, responseForError));
|
|
151
164
|
};
|
|
@@ -214,6 +227,8 @@ function getResponseForError(res) {
|
|
|
214
227
|
return responseForError;
|
|
215
228
|
}
|
|
216
229
|
|
|
230
|
+
const PROTOCOL_NUMBER = 0x00;
|
|
231
|
+
|
|
217
232
|
/**
|
|
218
233
|
* @description concat socket message and binary data pair into single binary data
|
|
219
234
|
* protocol is:
|
|
@@ -225,7 +240,7 @@ function getResponseForError(res) {
|
|
|
225
240
|
* @returns {Buffer}
|
|
226
241
|
*/
|
|
227
242
|
function createBufferFromSocketMessage([socketMessage, binaryData]) {
|
|
228
|
-
const protocolNumber =
|
|
243
|
+
const protocolNumber = PROTOCOL_NUMBER;
|
|
229
244
|
const socketMessageSizeMaxBytes = 4;
|
|
230
245
|
const socketMessageBuffer = Buffer.from(typeof socketMessage === 'string' ? socketMessage : JSON.stringify(socketMessage));
|
|
231
246
|
const sizeSocketMessage = Buffer.alloc(socketMessageSizeMaxBytes);
|
|
@@ -237,8 +252,36 @@ function createBufferFromSocketMessage([socketMessage, binaryData]) {
|
|
|
237
252
|
return Buffer.concat([header, socketMessageBuffer, binaryData]);
|
|
238
253
|
}
|
|
239
254
|
|
|
255
|
+
/**
|
|
256
|
+
* @param {Buffer} binarySocketMessage
|
|
257
|
+
* @returns {null | [string, Buffer]}
|
|
258
|
+
*/
|
|
259
|
+
function parseBinarySocketMessage(binarySocketMessage) {
|
|
260
|
+
const protocolBufferOffset = 1;
|
|
261
|
+
const jsonMessageDataSizeOffset = 4;
|
|
262
|
+
const headerOffset = protocolBufferOffset + jsonMessageDataSizeOffset;
|
|
263
|
+
const protocolNumber = binarySocketMessage[0];
|
|
264
|
+
|
|
265
|
+
if (protocolNumber !== PROTOCOL_NUMBER) {
|
|
266
|
+
return null;
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
const textSize = binarySocketMessage.readUInt32BE(protocolBufferOffset);
|
|
270
|
+
const textPart = binarySocketMessage.toString(
|
|
271
|
+
'utf-8',
|
|
272
|
+
headerOffset,
|
|
273
|
+
headerOffset + textSize,
|
|
274
|
+
);
|
|
275
|
+
const binaryPart = binarySocketMessage.subarray(headerOffset + textSize);
|
|
276
|
+
|
|
277
|
+
return [
|
|
278
|
+
textPart,
|
|
279
|
+
binaryPart,
|
|
280
|
+
];
|
|
281
|
+
}
|
|
240
282
|
module.exports = {
|
|
241
283
|
processServerResponse,
|
|
242
284
|
getRequestType,
|
|
243
285
|
createBufferFromSocketMessage,
|
|
286
|
+
parseBinarySocketMessage,
|
|
244
287
|
};
|
|
@@ -111,6 +111,11 @@ schemas[validationKeys.TAKE_SCREENSHOT] = {
|
|
|
111
111
|
'enum': ['raw', 'base64'],
|
|
112
112
|
};
|
|
113
113
|
|
|
114
|
+
schemas[validationKeys.LAST_SCREENSHOT] = {
|
|
115
|
+
'type': 'string',
|
|
116
|
+
'enum': ['raw', 'base64'],
|
|
117
|
+
};
|
|
118
|
+
|
|
114
119
|
schemas[validationKeys.UUID] = {
|
|
115
120
|
'type': 'string',
|
|
116
121
|
'format': 'uuid',
|
|
@@ -87,6 +87,9 @@ const validatorsMap = {
|
|
|
87
87
|
[validationKeys.TAKE_SCREENSHOT]: (value, text) => {
|
|
88
88
|
return validators.validateJsonSchema(validationKeys.TAKE_SCREENSHOT, value, text);
|
|
89
89
|
},
|
|
90
|
+
[validationKeys.LAST_SCREENSHOT]: (value, text) => {
|
|
91
|
+
return validators.validateJsonSchema(validationKeys.LAST_SCREENSHOT, value, text);
|
|
92
|
+
},
|
|
90
93
|
[validationKeys.TAP_TYPE_AND_DURATION]: ({tapType, tapDuration}, tapTypeErrorMsg, durationErrorMsg) => {
|
|
91
94
|
return validators.validateTapTypeAndDuration({tapType, tapDuration}, tapTypeErrorMsg, durationErrorMsg);
|
|
92
95
|
},
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "suitest-js-api",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.20.0",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"repository": "git@github.com:SuitestAutomation/suitest-js-api.git",
|
|
6
6
|
"author": "Suitest <hello@suite.st>",
|
|
@@ -94,7 +94,7 @@
|
|
|
94
94
|
},
|
|
95
95
|
"dependencies": {
|
|
96
96
|
"@suitest/smst-to-text": "^4.13.0",
|
|
97
|
-
"@suitest/translate": "^4.
|
|
97
|
+
"@suitest/translate": "^4.22.0",
|
|
98
98
|
"@types/node": "^14.0.10",
|
|
99
99
|
"ajv": "^6.12.2",
|
|
100
100
|
"ansi-regex": "^5.0.0",
|
package/suitest.js
CHANGED
|
@@ -17,6 +17,7 @@ const closeAppFactory = require('./lib/chains/closeAppChain');
|
|
|
17
17
|
const suspendAppFactory = require('./lib/chains/suspendAppChain');
|
|
18
18
|
const takeScreenshotFactory = require('./lib/chains/takeScreenshotChain');
|
|
19
19
|
const saveScreenshotFactory = require('./lib/chains/saveScreenshotChain');
|
|
20
|
+
const getLastVTScreenshotFactory = require('./lib/chains/getLastVTScreenshotChain');
|
|
20
21
|
const openUrlFactory = require('./lib/chains/openUrlChain');
|
|
21
22
|
const locationFactory = require('./lib/chains/locationChain');
|
|
22
23
|
const applicationFactory = require('./lib/chains/applicationChain');
|
|
@@ -139,6 +140,7 @@ class SUITEST_API extends EventEmitter {
|
|
|
139
140
|
const {runTestAssert} = runTestFactory(this);
|
|
140
141
|
const {takeScreenshot} = takeScreenshotFactory(this);
|
|
141
142
|
const {saveScreenshot} = saveScreenshotFactory(this);
|
|
143
|
+
const {getLastVTScreenshot} = getLastVTScreenshotFactory(this);
|
|
142
144
|
const {setScreenOrientation, setScreenOrientationAssert} = setScreenOrientationFactory(this);
|
|
143
145
|
const {openDeepLink, openDeepLinkAssert} = openDeepLinkFactory(this);
|
|
144
146
|
const {ocr, ocrAssert} = ocrFactory(this);
|
|
@@ -168,6 +170,7 @@ class SUITEST_API extends EventEmitter {
|
|
|
168
170
|
this.pollUrl = pollUrl;
|
|
169
171
|
this.takeScreenshot = takeScreenshot;
|
|
170
172
|
this.saveScreenshot = saveScreenshot;
|
|
173
|
+
this.getLastVTScreenshot = getLastVTScreenshot;
|
|
171
174
|
this.setScreenOrientation = setScreenOrientation;
|
|
172
175
|
this.openDeepLink = openDeepLink;
|
|
173
176
|
this.ocr = ocr;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import {
|
|
2
|
+
Abandable,
|
|
3
|
+
AbstractChain,
|
|
4
|
+
Thenable
|
|
5
|
+
} from './modifiers';
|
|
6
|
+
|
|
7
|
+
export interface GetLastVTScreenshotChain<TResult> extends
|
|
8
|
+
AbstractChain,
|
|
9
|
+
Abandable<GetLastVTScreenshotAbandonedChain>,
|
|
10
|
+
Thenable<TResult>
|
|
11
|
+
{}
|
|
12
|
+
|
|
13
|
+
interface GetLastVTScreenshotAbandonedChain extends AbstractChain {}
|