suitest-js-api 3.1.3 → 3.2.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 +4 -4
- package/lib/chains/pressButtonChain.js +35 -11
- package/lib/testLauncher/composeConfig.js +83 -39
- package/lib/texts.js +1 -0
- package/lib/utils/socketErrorMessages.js +1 -0
- package/package.json +2 -2
package/index.d.ts
CHANGED
|
@@ -85,8 +85,8 @@ declare namespace suitest {
|
|
|
85
85
|
pollUrl(url: string, response: string): PollUrlChain;
|
|
86
86
|
position(x: number, y: number): PositionChain;
|
|
87
87
|
relativePosition(x: number, y: number): RelativePosition;
|
|
88
|
-
press(key: string): PressButtonChain;
|
|
89
|
-
press(keys: string[]): PressButtonChain;
|
|
88
|
+
press(key: string, options?: { longPressMs?: string | number }): PressButtonChain;
|
|
89
|
+
press(keys: string[], options?: { longPressMs?: string | number }): PressButtonChain;
|
|
90
90
|
sleep(milliseconds: number): SleepChain;
|
|
91
91
|
window(): WindowChain;
|
|
92
92
|
|
|
@@ -190,8 +190,8 @@ declare namespace suitest {
|
|
|
190
190
|
pollUrl(url: string, response: string): PollUrlChain;
|
|
191
191
|
position(x: number, y: number): PositionChain;
|
|
192
192
|
relativePosition(x: number, y: number): RelativePosition;
|
|
193
|
-
press(key: string): PressButtonChain;
|
|
194
|
-
press(keys: string[]): PressButtonChain;
|
|
193
|
+
press(key: string, options?: { longPressMs?: string | number }): PressButtonChain;
|
|
194
|
+
press(keys: string[], options?: { longPressMs?: string | number }): PressButtonChain;
|
|
195
195
|
runTest(testId: string): RunTestChain;
|
|
196
196
|
sleep(milliseconds: number): SleepChain;
|
|
197
197
|
window(): WindowChain;
|
|
@@ -20,16 +20,24 @@ const {validate, validators} = require('../validation');
|
|
|
20
20
|
const {getRequestType} = require('../utils/socketChainHelper');
|
|
21
21
|
|
|
22
22
|
const pressButtonFactory = (classInstance) => {
|
|
23
|
-
const toJSON = (data) =>
|
|
24
|
-
|
|
25
|
-
request: compose(
|
|
26
|
-
msg => applyUntilCondition(msg, data),
|
|
27
|
-
msg => applyCountAndDelay(msg, data),
|
|
28
|
-
)({
|
|
23
|
+
const toJSON = (data) => {
|
|
24
|
+
const base = {
|
|
29
25
|
type: 'button',
|
|
30
26
|
ids: data.ids,
|
|
31
|
-
}
|
|
32
|
-
|
|
27
|
+
};
|
|
28
|
+
|
|
29
|
+
if (data.longPressMs !== undefined) {
|
|
30
|
+
base.longPressMs = data.longPressMs;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
return {
|
|
34
|
+
type: getRequestType(data, false),
|
|
35
|
+
request: compose(
|
|
36
|
+
msg => applyUntilCondition(msg, data),
|
|
37
|
+
msg => applyCountAndDelay(msg, data),
|
|
38
|
+
)(base),
|
|
39
|
+
};
|
|
40
|
+
};
|
|
33
41
|
|
|
34
42
|
const toStringComposer = makeToStringComposer(toJSON);
|
|
35
43
|
const thenComposer = makeThenComposer(toJSON);
|
|
@@ -67,18 +75,34 @@ const pressButtonFactory = (classInstance) => {
|
|
|
67
75
|
return output;
|
|
68
76
|
};
|
|
69
77
|
|
|
70
|
-
|
|
78
|
+
/**
|
|
79
|
+
* @param {string | string[]} buttonOrButtons
|
|
80
|
+
* @param {{longPressMs?: number}} [options]
|
|
81
|
+
* @returns {PressButtonChain}
|
|
82
|
+
*/
|
|
83
|
+
const pressButtonChain = (buttonOrButtons, options = {}) => {
|
|
71
84
|
const ids = Array.isArray(buttonOrButtons) ? buttonOrButtons : [buttonOrButtons];
|
|
72
85
|
|
|
73
86
|
return makeChain(classInstance, getComposers, {
|
|
74
87
|
type: 'press',
|
|
75
|
-
ids: validate(
|
|
88
|
+
ids: validate(
|
|
89
|
+
validators.ARRAY_OF_BUTTONS,
|
|
90
|
+
ids,
|
|
91
|
+
invalidInputMessage('pressButton', 'Illegal button ids.'),
|
|
92
|
+
),
|
|
93
|
+
longPressMs: options.longPressMs !== undefined
|
|
94
|
+
? validate(
|
|
95
|
+
validators.ST_VAR_OR_POSITIVE_NUMBER,
|
|
96
|
+
options.longPressMs,
|
|
97
|
+
invalidInputMessage('pressButton', 'Invalid longPressMs'),
|
|
98
|
+
)
|
|
99
|
+
: undefined,
|
|
76
100
|
});
|
|
77
101
|
};
|
|
78
102
|
|
|
79
103
|
return {
|
|
80
104
|
pressButton: pressButtonChain,
|
|
81
|
-
pressButtonAssert:
|
|
105
|
+
pressButtonAssert: (...args) => pressButtonChain(...args).toAssert(),
|
|
82
106
|
|
|
83
107
|
// For testing
|
|
84
108
|
toJSON,
|
|
@@ -17,33 +17,40 @@ const path = require('path');
|
|
|
17
17
|
const PRESETS = 'presets';
|
|
18
18
|
const APP_NAME = 'suitest';
|
|
19
19
|
const ETC_DIR = '/etc';
|
|
20
|
-
const
|
|
21
|
-
const HOME_DIR =
|
|
20
|
+
const IS_WINDOWS = process.platform === 'win32';
|
|
21
|
+
const HOME_DIR = IS_WINDOWS
|
|
22
22
|
? process.env.USERPROFILE
|
|
23
23
|
: process.env.HOME;
|
|
24
24
|
|
|
25
|
-
const
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
`.${APP_NAME}rc`,
|
|
25
|
+
const CONFIG_FORMATS = [
|
|
26
|
+
'.js',
|
|
27
|
+
'.json',
|
|
28
|
+
'.yaml',
|
|
29
|
+
'.yml',
|
|
30
|
+
'.json5',
|
|
31
|
+
'.ini',
|
|
33
32
|
];
|
|
34
33
|
|
|
35
34
|
/**
|
|
36
|
-
* @description
|
|
37
|
-
* @type {
|
|
35
|
+
* @description default directories to search. Logic the same as in rc
|
|
36
|
+
* @type {
|
|
37
|
+
* {
|
|
38
|
+
* path: string,
|
|
39
|
+
* filename: string,
|
|
40
|
+
* deepSearch: boolean,
|
|
41
|
+
* isGeneral: boolean
|
|
42
|
+
* } []
|
|
43
|
+
* }
|
|
38
44
|
*/
|
|
39
|
-
const
|
|
40
|
-
path.
|
|
41
|
-
path.join(HOME_DIR,
|
|
42
|
-
path.join(HOME_DIR, '.config', APP_NAME
|
|
43
|
-
path.join(HOME_DIR, '
|
|
44
|
-
path
|
|
45
|
-
|
|
46
|
-
|
|
45
|
+
const DEFAULT_PATHS = [
|
|
46
|
+
{path: process.cwd(), filename: `.${APP_NAME}rc`, deepSearch: true, isGeneral: true},
|
|
47
|
+
{path: path.join(HOME_DIR, '.config', APP_NAME), filename: 'config', deepSearch: false, isGeneral: true},
|
|
48
|
+
{path: path.join(HOME_DIR, '.config'), filename: APP_NAME, deepSearch: false, isGeneral: true},
|
|
49
|
+
{path: path.join(HOME_DIR, `.${APP_NAME}`), filename: 'config', deepSearch: false, isGeneral: true},
|
|
50
|
+
{path: HOME_DIR, filename: `.${APP_NAME}rc`, deepSearch: false, isGeneral: true},
|
|
51
|
+
|
|
52
|
+
{path: path.join(ETC_DIR, APP_NAME), filename: 'config', deepSearch: false, isGeneral: false},
|
|
53
|
+
{path: ETC_DIR, filename: `${APP_NAME}rc`, deepSearch: false, isGeneral: false},
|
|
47
54
|
];
|
|
48
55
|
|
|
49
56
|
/**
|
|
@@ -109,34 +116,73 @@ function findExtendConfigs(defaultConfigObject, extendPath, filePath, foundPaths
|
|
|
109
116
|
return mainConfigFile;
|
|
110
117
|
}
|
|
111
118
|
|
|
119
|
+
/**
|
|
120
|
+
* @description Search for configuration files.
|
|
121
|
+
* @param {String} pathToSearch path to directory to search
|
|
122
|
+
* @param {String} filename base filename without extension
|
|
123
|
+
*/
|
|
124
|
+
function findConfig(pathToSearch, filename) {
|
|
125
|
+
if (!fs.existsSync(pathToSearch)) {
|
|
126
|
+
return;
|
|
127
|
+
}
|
|
128
|
+
const files = fs.readdirSync(pathToSearch);
|
|
129
|
+
const file = files.find(file => {
|
|
130
|
+
const {name, ext} = path.parse(file);
|
|
131
|
+
|
|
132
|
+
return name === filename && (CONFIG_FORMATS.includes(ext) || !ext);
|
|
133
|
+
});
|
|
134
|
+
|
|
135
|
+
return file ? path.join(pathToSearch, file) : undefined;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* @description Search for configuration files up to the root.
|
|
140
|
+
* @param {String} pathToSearch path to directory to search
|
|
141
|
+
* @param {String} filename base filename without extension
|
|
142
|
+
*/
|
|
143
|
+
function findConfigUpToRoot(pathToSearch, filename) {
|
|
144
|
+
const foundConfigFile = findConfig(pathToSearch, filename);
|
|
145
|
+
|
|
146
|
+
if (foundConfigFile || path.parse(pathToSearch).root === pathToSearch) {
|
|
147
|
+
return foundConfigFile;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
return findConfigUpToRoot(path.join(pathToSearch, '../'), filename);
|
|
151
|
+
}
|
|
152
|
+
|
|
112
153
|
/**
|
|
113
154
|
* Read `.suitestrc` launcher config file.
|
|
155
|
+
* Also, searches for default RC paths.
|
|
114
156
|
* If file not found, return empty object.
|
|
115
|
-
* Supports json
|
|
157
|
+
* Supports json, json5, js, yaml, yml, ini formats.
|
|
158
|
+
* Searches for 'extends' property for other config file and if presents merge them.
|
|
116
159
|
* cli arguments are not parsed.
|
|
117
160
|
* If file found, but json invalid, throw error.
|
|
118
161
|
* @returns {Object}
|
|
119
162
|
*/
|
|
120
163
|
function readRcConfig(pathToConfig) {
|
|
121
164
|
let mainConfigFilePath = '';
|
|
122
|
-
const foundFiles = [];
|
|
123
165
|
|
|
124
166
|
if (pathToConfig) {
|
|
125
|
-
foundFiles.push(pathToConfig);
|
|
126
167
|
mainConfigFilePath = pathToConfig;
|
|
127
168
|
} else {
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
if (files.length > 0) {
|
|
135
|
-
mainConfigFilePath = files[0];
|
|
136
|
-
foundFiles.push(files[0]);
|
|
137
|
-
}
|
|
169
|
+
const defaultConfigurations = DEFAULT_PATHS
|
|
170
|
+
.filter(defaultConfig => IS_WINDOWS ? defaultConfig.isGeneral : true);
|
|
171
|
+
|
|
172
|
+
for (const defaultConfig of defaultConfigurations) {
|
|
173
|
+
if (mainConfigFilePath) {
|
|
174
|
+
break;
|
|
138
175
|
}
|
|
139
|
-
|
|
176
|
+
if (
|
|
177
|
+
fs.existsSync(defaultConfig.path) &&
|
|
178
|
+
fs.lstatSync(defaultConfig.path).isDirectory()
|
|
179
|
+
) {
|
|
180
|
+
mainConfigFilePath = (
|
|
181
|
+
defaultConfig.deepSearch ?
|
|
182
|
+
findConfigUpToRoot :
|
|
183
|
+
findConfig)(defaultConfig.path, defaultConfig.filename);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
140
186
|
}
|
|
141
187
|
|
|
142
188
|
if (!mainConfigFilePath) {
|
|
@@ -151,17 +197,15 @@ function readRcConfig(pathToConfig) {
|
|
|
151
197
|
configFile,
|
|
152
198
|
configFile.extends,
|
|
153
199
|
mainConfigFilePath,
|
|
154
|
-
[
|
|
200
|
+
[mainConfigFilePath],
|
|
155
201
|
),
|
|
156
|
-
|
|
157
|
-
config: foundFiles[0],
|
|
202
|
+
config: mainConfigFilePath,
|
|
158
203
|
};
|
|
159
204
|
}
|
|
160
205
|
|
|
161
206
|
return {
|
|
162
207
|
...configFile,
|
|
163
|
-
|
|
164
|
-
config: foundFiles[0],
|
|
208
|
+
config: mainConfigFilePath,
|
|
165
209
|
};
|
|
166
210
|
}
|
|
167
211
|
|
package/lib/texts.js
CHANGED
|
@@ -149,6 +149,7 @@ ${leaves}`,
|
|
|
149
149
|
'commandError.timeout': () => 'Failed to take a screenshot due to timeout.',
|
|
150
150
|
'commandError.generalError': () => 'Failed to take a screenshot.',
|
|
151
151
|
'commandError.notSupportedDriver': () => 'Screenshots are not supported on this driver.',
|
|
152
|
+
'commandError.screenshotFailed': () => 'Error while taking screenshot of device. Saved file does not exists or is not readable.',
|
|
152
153
|
|
|
153
154
|
executorStopped: () => 'Test execution was stopped. See our documentation for possible reasons: https://suite.st/docs/error-messages/results-errors/#test-execution-was-stopped',
|
|
154
155
|
|
|
@@ -99,6 +99,7 @@ const commandErrors = {
|
|
|
99
99
|
'timeout': () => t['commandError.timeout'](),
|
|
100
100
|
'generalError': () => t['commandError.generalError'](),
|
|
101
101
|
'notSupportedDriver': () => t['commandError.notSupportedDriver'](),
|
|
102
|
+
'screenshotFailed': () => t['commandError.screenshotFailed'](),
|
|
102
103
|
};
|
|
103
104
|
|
|
104
105
|
/**
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "suitest-js-api",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.2.0",
|
|
4
4
|
"main": "index.js",
|
|
5
5
|
"repository": "git@github.com:SuitestAutomation/suitest-js-api.git",
|
|
6
6
|
"author": "Suitest <hello@suite.st>",
|
|
@@ -85,7 +85,7 @@
|
|
|
85
85
|
},
|
|
86
86
|
"dependencies": {
|
|
87
87
|
"@suitest/smst-to-text": "^4.4.3",
|
|
88
|
-
"@suitest/translate": "^4.4.
|
|
88
|
+
"@suitest/translate": "^4.4.4",
|
|
89
89
|
"@types/node": "^14.0.10",
|
|
90
90
|
"ajv": "^6.12.2",
|
|
91
91
|
"ansi-regex": "^5.0.0",
|