codeceptjs 3.6.10 → 3.7.0-beta.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 +81 -110
- package/bin/codecept.js +2 -2
- package/docs/webapi/clearCookie.mustache +1 -1
- package/lib/actor.js +46 -36
- package/lib/assert/empty.js +3 -5
- package/lib/assert/equal.js +4 -7
- package/lib/assert/include.js +4 -6
- package/lib/assert/throws.js +2 -4
- package/lib/assert/truth.js +2 -2
- package/lib/codecept.js +87 -83
- package/lib/command/configMigrate.js +2 -4
- package/lib/command/definitions.js +5 -25
- package/lib/command/generate.js +10 -14
- package/lib/command/gherkin/snippets.js +10 -8
- package/lib/command/gherkin/steps.js +1 -1
- package/lib/command/info.js +1 -3
- package/lib/command/init.js +8 -12
- package/lib/command/interactive.js +1 -1
- package/lib/command/list.js +1 -1
- package/lib/command/run-multiple.js +12 -35
- package/lib/command/run-workers.js +10 -10
- package/lib/command/utils.js +5 -6
- package/lib/command/workers/runTests.js +14 -17
- package/lib/container.js +327 -237
- package/lib/data/context.js +10 -13
- package/lib/data/dataScenarioConfig.js +8 -8
- package/lib/data/dataTableArgument.js +6 -6
- package/lib/data/table.js +5 -11
- package/lib/els.js +177 -0
- package/lib/event.js +1 -0
- package/lib/heal.js +78 -80
- package/lib/helper/ApiDataFactory.js +3 -6
- package/lib/helper/Appium.js +15 -30
- package/lib/helper/FileSystem.js +3 -3
- package/lib/helper/GraphQLDataFactory.js +3 -3
- package/lib/helper/JSONResponse.js +57 -37
- package/lib/helper/Nightmare.js +35 -53
- package/lib/helper/Playwright.js +189 -251
- package/lib/helper/Protractor.js +54 -77
- package/lib/helper/Puppeteer.js +134 -232
- package/lib/helper/REST.js +5 -17
- package/lib/helper/TestCafe.js +21 -44
- package/lib/helper/WebDriver.js +103 -162
- package/lib/helper/testcafe/testcafe-utils.js +26 -27
- package/lib/listener/artifacts.js +2 -2
- package/lib/listener/emptyRun.js +58 -0
- package/lib/listener/exit.js +4 -4
- package/lib/listener/{retry.js → globalRetry.js} +5 -5
- package/lib/listener/{timeout.js → globalTimeout.js} +8 -8
- package/lib/listener/helpers.js +15 -15
- package/lib/listener/mocha.js +1 -1
- package/lib/listener/steps.js +17 -12
- package/lib/listener/store.js +12 -0
- package/lib/mocha/asyncWrapper.js +204 -0
- package/lib/{interfaces → mocha}/bdd.js +3 -3
- package/lib/mocha/cli.js +257 -0
- package/lib/mocha/factory.js +104 -0
- package/lib/{interfaces → mocha}/featureConfig.js +11 -12
- package/lib/{interfaces → mocha}/gherkin.js +26 -28
- package/lib/mocha/hooks.js +83 -0
- package/lib/mocha/index.js +12 -0
- package/lib/mocha/inject.js +24 -0
- package/lib/{interfaces → mocha}/scenarioConfig.js +10 -6
- package/lib/mocha/suite.js +55 -0
- package/lib/mocha/test.js +60 -0
- package/lib/mocha/types.d.ts +31 -0
- package/lib/mocha/ui.js +219 -0
- package/lib/output.js +28 -10
- package/lib/pause.js +159 -135
- package/lib/plugin/autoDelay.js +4 -4
- package/lib/plugin/autoLogin.js +6 -7
- package/lib/plugin/commentStep.js +1 -1
- package/lib/plugin/coverage.js +10 -19
- package/lib/plugin/customLocator.js +3 -3
- package/lib/plugin/debugErrors.js +2 -2
- package/lib/plugin/eachElement.js +1 -1
- package/lib/plugin/fakerTransform.js +1 -1
- package/lib/plugin/heal.js +6 -9
- package/lib/plugin/retryFailedStep.js +4 -4
- package/lib/plugin/retryTo.js +2 -2
- package/lib/plugin/screenshotOnFail.js +9 -36
- package/lib/plugin/selenoid.js +15 -35
- package/lib/plugin/stepByStepReport.js +51 -13
- package/lib/plugin/stepTimeout.js +4 -11
- package/lib/plugin/subtitles.js +4 -4
- package/lib/plugin/tryTo.js +1 -1
- package/lib/plugin/wdio.js +8 -10
- package/lib/recorder.js +142 -121
- package/lib/secret.js +1 -1
- package/lib/step.js +160 -144
- package/lib/store.js +6 -2
- package/lib/template/heal.js +2 -11
- package/lib/utils.js +224 -216
- package/lib/within.js +73 -55
- package/lib/workers.js +265 -261
- package/package.json +46 -47
- package/typings/index.d.ts +172 -184
- package/typings/promiseBasedTypes.d.ts +53 -516
- package/typings/types.d.ts +127 -587
- package/lib/cli.js +0 -256
- package/lib/helper/ExpectHelper.js +0 -391
- package/lib/helper/SoftExpectHelper.js +0 -381
- package/lib/mochaFactory.js +0 -113
- package/lib/scenario.js +0 -224
- package/lib/ui.js +0 -236
package/lib/utils.js
CHANGED
|
@@ -1,104 +1,93 @@
|
|
|
1
|
-
const fs = require('fs')
|
|
2
|
-
const os = require('os')
|
|
3
|
-
const path = require('path')
|
|
4
|
-
const getFunctionArguments = require('fn-args')
|
|
5
|
-
const deepClone = require('lodash.clonedeep')
|
|
6
|
-
const { convertColorToRGBA, isColorProperty } = require('./colorUtils')
|
|
1
|
+
const fs = require('fs')
|
|
2
|
+
const os = require('os')
|
|
3
|
+
const path = require('path')
|
|
4
|
+
const getFunctionArguments = require('fn-args')
|
|
5
|
+
const deepClone = require('lodash.clonedeep')
|
|
6
|
+
const { convertColorToRGBA, isColorProperty } = require('./colorUtils')
|
|
7
7
|
|
|
8
8
|
function deepMerge(target, source) {
|
|
9
|
-
const merge = require('lodash.merge')
|
|
10
|
-
return merge(target, source)
|
|
9
|
+
const merge = require('lodash.merge')
|
|
10
|
+
return merge(target, source)
|
|
11
11
|
}
|
|
12
12
|
|
|
13
|
-
module.exports.genTestId =
|
|
14
|
-
return require('crypto').createHash('sha256').update(test.fullTitle()).digest('base64')
|
|
15
|
-
|
|
16
|
-
};
|
|
13
|
+
module.exports.genTestId = test => {
|
|
14
|
+
return require('crypto').createHash('sha256').update(test.fullTitle()).digest('base64').slice(0, -2)
|
|
15
|
+
}
|
|
17
16
|
|
|
18
|
-
module.exports.deepMerge = deepMerge
|
|
17
|
+
module.exports.deepMerge = deepMerge
|
|
19
18
|
|
|
20
|
-
module.exports.deepClone = deepClone
|
|
19
|
+
module.exports.deepClone = deepClone
|
|
21
20
|
|
|
22
21
|
module.exports.isGenerator = function (fn) {
|
|
23
|
-
return fn.constructor.name === 'GeneratorFunction'
|
|
24
|
-
}
|
|
22
|
+
return fn.constructor.name === 'GeneratorFunction'
|
|
23
|
+
}
|
|
25
24
|
|
|
26
|
-
const isFunction = module.exports.isFunction = function (fn) {
|
|
27
|
-
return typeof fn === 'function'
|
|
28
|
-
}
|
|
25
|
+
const isFunction = (module.exports.isFunction = function (fn) {
|
|
26
|
+
return typeof fn === 'function'
|
|
27
|
+
})
|
|
29
28
|
|
|
30
|
-
const isAsyncFunction = module.exports.isAsyncFunction = function (fn) {
|
|
31
|
-
if (!fn) return false
|
|
32
|
-
return fn[Symbol.toStringTag] === 'AsyncFunction'
|
|
33
|
-
}
|
|
29
|
+
const isAsyncFunction = (module.exports.isAsyncFunction = function (fn) {
|
|
30
|
+
if (!fn) return false
|
|
31
|
+
return fn[Symbol.toStringTag] === 'AsyncFunction'
|
|
32
|
+
})
|
|
34
33
|
|
|
35
34
|
module.exports.fileExists = function (filePath) {
|
|
36
|
-
return fs.existsSync(filePath)
|
|
37
|
-
}
|
|
35
|
+
return fs.existsSync(filePath)
|
|
36
|
+
}
|
|
38
37
|
|
|
39
38
|
module.exports.isFile = function (filePath) {
|
|
40
|
-
let filestat
|
|
39
|
+
let filestat
|
|
41
40
|
try {
|
|
42
|
-
filestat = fs.statSync(filePath)
|
|
41
|
+
filestat = fs.statSync(filePath)
|
|
43
42
|
} catch (err) {
|
|
44
|
-
if (err.code === 'ENOENT') return false
|
|
43
|
+
if (err.code === 'ENOENT') return false
|
|
45
44
|
}
|
|
46
|
-
if (!filestat) return false
|
|
47
|
-
return filestat.isFile()
|
|
48
|
-
}
|
|
45
|
+
if (!filestat) return false
|
|
46
|
+
return filestat.isFile()
|
|
47
|
+
}
|
|
49
48
|
|
|
50
49
|
module.exports.getParamNames = function (fn) {
|
|
51
|
-
if (fn.isSinonProxy) return []
|
|
52
|
-
return getFunctionArguments(fn)
|
|
53
|
-
}
|
|
50
|
+
if (fn.isSinonProxy) return []
|
|
51
|
+
return getFunctionArguments(fn)
|
|
52
|
+
}
|
|
54
53
|
|
|
55
54
|
module.exports.installedLocally = function () {
|
|
56
|
-
return path.resolve(`${__dirname}/../`).indexOf(process.cwd()) === 0
|
|
57
|
-
}
|
|
55
|
+
return path.resolve(`${__dirname}/../`).indexOf(process.cwd()) === 0
|
|
56
|
+
}
|
|
58
57
|
|
|
59
58
|
module.exports.methodsOfObject = function (obj, className) {
|
|
60
|
-
const methods = []
|
|
61
|
-
|
|
62
|
-
const standard = [
|
|
63
|
-
'constructor',
|
|
64
|
-
'toString',
|
|
65
|
-
'toLocaleString',
|
|
66
|
-
'valueOf',
|
|
67
|
-
'hasOwnProperty',
|
|
68
|
-
'bind',
|
|
69
|
-
'apply',
|
|
70
|
-
'call',
|
|
71
|
-
'isPrototypeOf',
|
|
72
|
-
'propertyIsEnumerable',
|
|
73
|
-
];
|
|
59
|
+
const methods = []
|
|
60
|
+
|
|
61
|
+
const standard = ['constructor', 'toString', 'toLocaleString', 'valueOf', 'hasOwnProperty', 'bind', 'apply', 'call', 'isPrototypeOf', 'propertyIsEnumerable']
|
|
74
62
|
|
|
75
63
|
function pushToMethods(prop) {
|
|
76
64
|
try {
|
|
77
|
-
if (!isFunction(obj[prop]) && !isAsyncFunction(obj[prop])) return
|
|
78
|
-
} catch (err) {
|
|
79
|
-
|
|
65
|
+
if (!isFunction(obj[prop]) && !isAsyncFunction(obj[prop])) return
|
|
66
|
+
} catch (err) {
|
|
67
|
+
// can't access property
|
|
68
|
+
return
|
|
80
69
|
}
|
|
81
|
-
if (standard.indexOf(prop) >= 0) return
|
|
82
|
-
if (prop.indexOf('_') === 0) return
|
|
83
|
-
methods.push(prop)
|
|
70
|
+
if (standard.indexOf(prop) >= 0) return
|
|
71
|
+
if (prop.indexOf('_') === 0) return
|
|
72
|
+
methods.push(prop)
|
|
84
73
|
}
|
|
85
74
|
|
|
86
75
|
while (obj.constructor.name !== className) {
|
|
87
|
-
Object.getOwnPropertyNames(obj).forEach(pushToMethods)
|
|
88
|
-
obj = Object.getPrototypeOf(obj)
|
|
76
|
+
Object.getOwnPropertyNames(obj).forEach(pushToMethods)
|
|
77
|
+
obj = Object.getPrototypeOf(obj)
|
|
89
78
|
|
|
90
|
-
if (!obj || !obj.constructor) break
|
|
79
|
+
if (!obj || !obj.constructor) break
|
|
91
80
|
}
|
|
92
|
-
return methods
|
|
93
|
-
}
|
|
81
|
+
return methods
|
|
82
|
+
}
|
|
94
83
|
|
|
95
84
|
module.exports.template = function (template, data) {
|
|
96
85
|
return template.replace(/{{([^{}]*)}}/g, (a, b) => {
|
|
97
|
-
const r = data[b]
|
|
98
|
-
if (r === undefined) return ''
|
|
99
|
-
return r.toString()
|
|
100
|
-
})
|
|
101
|
-
}
|
|
86
|
+
const r = data[b]
|
|
87
|
+
if (r === undefined) return ''
|
|
88
|
+
return r.toString()
|
|
89
|
+
})
|
|
90
|
+
}
|
|
102
91
|
|
|
103
92
|
/**
|
|
104
93
|
* Make first char uppercase.
|
|
@@ -106,8 +95,8 @@ module.exports.template = function (template, data) {
|
|
|
106
95
|
* @returns {string}
|
|
107
96
|
*/
|
|
108
97
|
module.exports.ucfirst = function (str) {
|
|
109
|
-
return str.charAt(0).toUpperCase() + str.substr(1)
|
|
110
|
-
}
|
|
98
|
+
return str.charAt(0).toUpperCase() + str.substr(1)
|
|
99
|
+
}
|
|
111
100
|
|
|
112
101
|
/**
|
|
113
102
|
* Make first char lowercase.
|
|
@@ -115,25 +104,25 @@ module.exports.ucfirst = function (str) {
|
|
|
115
104
|
* @returns {string}
|
|
116
105
|
*/
|
|
117
106
|
module.exports.lcfirst = function (str) {
|
|
118
|
-
return str.charAt(0).toLowerCase() + str.substr(1)
|
|
119
|
-
}
|
|
107
|
+
return str.charAt(0).toLowerCase() + str.substr(1)
|
|
108
|
+
}
|
|
120
109
|
|
|
121
110
|
module.exports.chunkArray = function (arr, chunk) {
|
|
122
|
-
let i
|
|
123
|
-
let j
|
|
124
|
-
const tmp = []
|
|
111
|
+
let i
|
|
112
|
+
let j
|
|
113
|
+
const tmp = []
|
|
125
114
|
for (i = 0, j = arr.length; i < j; i += chunk) {
|
|
126
|
-
tmp.push(arr.slice(i, i + chunk))
|
|
115
|
+
tmp.push(arr.slice(i, i + chunk))
|
|
127
116
|
}
|
|
128
|
-
return tmp
|
|
129
|
-
}
|
|
117
|
+
return tmp
|
|
118
|
+
}
|
|
130
119
|
|
|
131
120
|
module.exports.clearString = function (str) {
|
|
132
|
-
if (!str) return ''
|
|
121
|
+
if (!str) return ''
|
|
133
122
|
/* Replace forbidden symbols in string
|
|
134
123
|
*/
|
|
135
124
|
if (str.endsWith('.')) {
|
|
136
|
-
str = str.slice(0, -1)
|
|
125
|
+
str = str.slice(0, -1)
|
|
137
126
|
}
|
|
138
127
|
return str
|
|
139
128
|
.replace(/ /g, '_')
|
|
@@ -146,26 +135,29 @@ module.exports.clearString = function (str) {
|
|
|
146
135
|
.replace(/\|/g, '_')
|
|
147
136
|
.replace(/\?/g, '.')
|
|
148
137
|
.replace(/\*/g, '^')
|
|
149
|
-
.replace(/'/g, '')
|
|
150
|
-
}
|
|
138
|
+
.replace(/'/g, '')
|
|
139
|
+
}
|
|
151
140
|
|
|
152
141
|
module.exports.decodeUrl = function (url) {
|
|
153
142
|
/* Replace forbidden symbols in string
|
|
154
143
|
*/
|
|
155
|
-
return decodeURIComponent(decodeURIComponent(decodeURIComponent(url)))
|
|
156
|
-
}
|
|
144
|
+
return decodeURIComponent(decodeURIComponent(decodeURIComponent(url)))
|
|
145
|
+
}
|
|
157
146
|
|
|
158
147
|
module.exports.xpathLocator = {
|
|
159
148
|
/**
|
|
160
149
|
* @param {string} string
|
|
161
150
|
* @returns {string}
|
|
162
151
|
*/
|
|
163
|
-
literal:
|
|
152
|
+
literal: string => {
|
|
164
153
|
if (string.indexOf("'") > -1) {
|
|
165
|
-
string = string
|
|
166
|
-
|
|
154
|
+
string = string
|
|
155
|
+
.split("'", -1)
|
|
156
|
+
.map(substr => `'${substr}'`)
|
|
157
|
+
.join(',"\'",')
|
|
158
|
+
return `concat(${string})`
|
|
167
159
|
}
|
|
168
|
-
return `'${string}'
|
|
160
|
+
return `'${string}'`
|
|
169
161
|
},
|
|
170
162
|
|
|
171
163
|
/**
|
|
@@ -174,55 +166,53 @@ module.exports.xpathLocator = {
|
|
|
174
166
|
* @returns {string}
|
|
175
167
|
*/
|
|
176
168
|
combine: locators => locators.join(' | '),
|
|
177
|
-
}
|
|
169
|
+
}
|
|
178
170
|
|
|
179
171
|
module.exports.test = {
|
|
180
|
-
|
|
181
172
|
grepLines(array, startString, endString) {
|
|
182
|
-
let startIndex = 0
|
|
183
|
-
let endIndex
|
|
173
|
+
let startIndex = 0
|
|
174
|
+
let endIndex
|
|
184
175
|
array.every((elem, index) => {
|
|
185
176
|
if (elem === startString) {
|
|
186
|
-
startIndex = index
|
|
187
|
-
return true
|
|
177
|
+
startIndex = index
|
|
178
|
+
return true
|
|
188
179
|
}
|
|
189
180
|
if (elem === endString) {
|
|
190
|
-
endIndex = index
|
|
191
|
-
return false
|
|
181
|
+
endIndex = index
|
|
182
|
+
return false
|
|
192
183
|
}
|
|
193
|
-
return true
|
|
194
|
-
})
|
|
195
|
-
return array.slice(startIndex + 1, endIndex)
|
|
184
|
+
return true
|
|
185
|
+
})
|
|
186
|
+
return array.slice(startIndex + 1, endIndex)
|
|
196
187
|
},
|
|
197
188
|
|
|
198
189
|
submittedData(dataFile) {
|
|
199
190
|
return function (key) {
|
|
200
191
|
if (!fs.existsSync(dataFile)) {
|
|
201
|
-
const waitTill = new Date(new Date().getTime() + 1 * 1000)
|
|
202
|
-
while (waitTill > new Date()) {}
|
|
192
|
+
const waitTill = new Date(new Date().getTime() + 1 * 1000) // wait for one sec for file to be created
|
|
193
|
+
while (waitTill > new Date()) {}
|
|
203
194
|
}
|
|
204
195
|
if (!fs.existsSync(dataFile)) {
|
|
205
|
-
throw new Error('Data file was not created in time')
|
|
196
|
+
throw new Error('Data file was not created in time')
|
|
206
197
|
}
|
|
207
|
-
const data = JSON.parse(fs.readFileSync(dataFile, 'utf8'))
|
|
198
|
+
const data = JSON.parse(fs.readFileSync(dataFile, 'utf8'))
|
|
208
199
|
if (key) {
|
|
209
|
-
return data.form[key]
|
|
200
|
+
return data.form[key]
|
|
210
201
|
}
|
|
211
|
-
return data
|
|
212
|
-
}
|
|
202
|
+
return data
|
|
203
|
+
}
|
|
213
204
|
},
|
|
214
|
-
|
|
215
|
-
};
|
|
205
|
+
}
|
|
216
206
|
|
|
217
207
|
function toCamelCase(name) {
|
|
218
208
|
if (typeof name !== 'string') {
|
|
219
|
-
return name
|
|
209
|
+
return name
|
|
220
210
|
}
|
|
221
211
|
return name.replace(/-(\w)/gi, (_word, letter) => {
|
|
222
|
-
return letter.toUpperCase()
|
|
223
|
-
})
|
|
212
|
+
return letter.toUpperCase()
|
|
213
|
+
})
|
|
224
214
|
}
|
|
225
|
-
module.exports.toCamelCase = toCamelCase
|
|
215
|
+
module.exports.toCamelCase = toCamelCase
|
|
226
216
|
|
|
227
217
|
function convertFontWeightToNumber(name) {
|
|
228
218
|
const fontWeightPatterns = [
|
|
@@ -235,106 +225,110 @@ function convertFontWeightToNumber(name) {
|
|
|
235
225
|
{ num: 700, pattern: /^Bold$/i },
|
|
236
226
|
{ num: 800, pattern: /^(Extra|Ultra)-?bold$/i },
|
|
237
227
|
{ num: 900, pattern: /^(Black|Heavy)$/i },
|
|
238
|
-
]
|
|
228
|
+
]
|
|
239
229
|
|
|
240
230
|
if (/^[1-9]00$/.test(name)) {
|
|
241
|
-
return Number(name)
|
|
231
|
+
return Number(name)
|
|
242
232
|
}
|
|
243
233
|
|
|
244
|
-
const matches = fontWeightPatterns.filter(fontWeight => fontWeight.pattern.test(name))
|
|
234
|
+
const matches = fontWeightPatterns.filter(fontWeight => fontWeight.pattern.test(name))
|
|
245
235
|
|
|
246
236
|
if (matches.length) {
|
|
247
|
-
return String(matches[0].num)
|
|
237
|
+
return String(matches[0].num)
|
|
248
238
|
}
|
|
249
|
-
return name
|
|
239
|
+
return name
|
|
250
240
|
}
|
|
251
241
|
|
|
252
242
|
function isFontWeightProperty(prop) {
|
|
253
|
-
return prop === 'fontWeight'
|
|
243
|
+
return prop === 'fontWeight'
|
|
254
244
|
}
|
|
255
245
|
|
|
256
246
|
module.exports.convertCssPropertiesToCamelCase = function (props) {
|
|
257
|
-
const output = {}
|
|
258
|
-
Object.keys(props).forEach(
|
|
259
|
-
const keyCamel = toCamelCase(key)
|
|
247
|
+
const output = {}
|
|
248
|
+
Object.keys(props).forEach(key => {
|
|
249
|
+
const keyCamel = toCamelCase(key)
|
|
260
250
|
|
|
261
251
|
if (isFontWeightProperty(keyCamel)) {
|
|
262
|
-
output[keyCamel] = convertFontWeightToNumber(props[key])
|
|
252
|
+
output[keyCamel] = convertFontWeightToNumber(props[key])
|
|
263
253
|
} else if (isColorProperty(keyCamel)) {
|
|
264
|
-
output[keyCamel] = convertColorToRGBA(props[key])
|
|
254
|
+
output[keyCamel] = convertColorToRGBA(props[key])
|
|
265
255
|
} else {
|
|
266
|
-
output[keyCamel] = props[key]
|
|
256
|
+
output[keyCamel] = props[key]
|
|
267
257
|
}
|
|
268
|
-
})
|
|
269
|
-
return output
|
|
270
|
-
}
|
|
258
|
+
})
|
|
259
|
+
return output
|
|
260
|
+
}
|
|
271
261
|
|
|
272
262
|
module.exports.deleteDir = function (dir_path) {
|
|
273
263
|
if (fs.existsSync(dir_path)) {
|
|
274
264
|
fs.readdirSync(dir_path).forEach(function (entry) {
|
|
275
|
-
const entry_path = path.join(dir_path, entry)
|
|
265
|
+
const entry_path = path.join(dir_path, entry)
|
|
276
266
|
if (fs.lstatSync(entry_path).isDirectory()) {
|
|
277
|
-
this.deleteDir(entry_path)
|
|
267
|
+
this.deleteDir(entry_path)
|
|
278
268
|
} else {
|
|
279
|
-
fs.unlinkSync(entry_path)
|
|
269
|
+
fs.unlinkSync(entry_path)
|
|
280
270
|
}
|
|
281
|
-
})
|
|
282
|
-
fs.rmdirSync(dir_path)
|
|
271
|
+
})
|
|
272
|
+
fs.rmdirSync(dir_path)
|
|
283
273
|
}
|
|
284
|
-
}
|
|
274
|
+
}
|
|
285
275
|
|
|
286
276
|
/**
|
|
287
277
|
* Returns absolute filename to save screenshot.
|
|
288
278
|
* @param fileName {string} - filename.
|
|
289
279
|
*/
|
|
290
280
|
module.exports.screenshotOutputFolder = function (fileName) {
|
|
291
|
-
const fileSep = path.sep
|
|
281
|
+
const fileSep = path.sep
|
|
292
282
|
|
|
293
283
|
if (!fileName.includes(fileSep) || fileName.includes('record_')) {
|
|
294
|
-
return path.resolve(global.output_dir, fileName)
|
|
284
|
+
return path.resolve(global.output_dir, fileName)
|
|
295
285
|
}
|
|
296
|
-
return path.resolve(global.codecept_dir, fileName)
|
|
297
|
-
}
|
|
286
|
+
return path.resolve(global.codecept_dir, fileName)
|
|
287
|
+
}
|
|
288
|
+
|
|
289
|
+
module.exports.relativeDir = function (fileName) {
|
|
290
|
+
return fileName.replace(global.codecept_dir, '').replace(/^\//, '')
|
|
291
|
+
}
|
|
298
292
|
|
|
299
293
|
module.exports.beautify = function (code) {
|
|
300
|
-
const format = require('js-beautify').js
|
|
301
|
-
return format(code, { indent_size: 2, space_in_empty_paren: true })
|
|
302
|
-
}
|
|
294
|
+
const format = require('js-beautify').js
|
|
295
|
+
return format(code, { indent_size: 2, space_in_empty_paren: true })
|
|
296
|
+
}
|
|
303
297
|
|
|
304
298
|
function shouldAppendBaseUrl(url) {
|
|
305
|
-
return !/^\w+\:\/\//.test(url)
|
|
299
|
+
return !/^\w+\:\/\//.test(url)
|
|
306
300
|
}
|
|
307
301
|
|
|
308
302
|
function trimUrl(url) {
|
|
309
|
-
const firstChar = url.substr(1)
|
|
303
|
+
const firstChar = url.substr(1)
|
|
310
304
|
if (firstChar === '/') {
|
|
311
|
-
url = url.slice(1)
|
|
305
|
+
url = url.slice(1)
|
|
312
306
|
}
|
|
313
|
-
return url
|
|
307
|
+
return url
|
|
314
308
|
}
|
|
315
309
|
|
|
316
310
|
function joinUrl(baseUrl, url) {
|
|
317
|
-
return shouldAppendBaseUrl(url) ? `${baseUrl}/${trimUrl(url)}` : url
|
|
311
|
+
return shouldAppendBaseUrl(url) ? `${baseUrl}/${trimUrl(url)}` : url
|
|
318
312
|
}
|
|
319
313
|
|
|
320
314
|
module.exports.appendBaseUrl = function (baseUrl = '', oneOrMoreUrls) {
|
|
321
315
|
if (typeof baseUrl !== 'string') {
|
|
322
|
-
throw new Error(`Invalid value for baseUrl: ${baseUrl}`)
|
|
316
|
+
throw new Error(`Invalid value for baseUrl: ${baseUrl}`)
|
|
323
317
|
}
|
|
324
318
|
if (!(typeof oneOrMoreUrls === 'string' || Array.isArray(oneOrMoreUrls))) {
|
|
325
|
-
throw new Error(`Expected type of Urls is 'string' or 'array', Found '${typeof oneOrMoreUrls}'.`)
|
|
319
|
+
throw new Error(`Expected type of Urls is 'string' or 'array', Found '${typeof oneOrMoreUrls}'.`)
|
|
326
320
|
}
|
|
327
321
|
// Remove '/' if it's at the end of baseUrl
|
|
328
|
-
const lastChar = baseUrl.substr(-1)
|
|
322
|
+
const lastChar = baseUrl.substr(-1)
|
|
329
323
|
if (lastChar === '/') {
|
|
330
|
-
baseUrl = baseUrl.slice(0, -1)
|
|
324
|
+
baseUrl = baseUrl.slice(0, -1)
|
|
331
325
|
}
|
|
332
326
|
|
|
333
327
|
if (!Array.isArray(oneOrMoreUrls)) {
|
|
334
|
-
return joinUrl(baseUrl, oneOrMoreUrls)
|
|
328
|
+
return joinUrl(baseUrl, oneOrMoreUrls)
|
|
335
329
|
}
|
|
336
|
-
return oneOrMoreUrls.map(url => joinUrl(baseUrl, url))
|
|
337
|
-
}
|
|
330
|
+
return oneOrMoreUrls.map(url => joinUrl(baseUrl, url))
|
|
331
|
+
}
|
|
338
332
|
|
|
339
333
|
/**
|
|
340
334
|
* Recursively search key in object and replace it's value.
|
|
@@ -344,56 +338,53 @@ module.exports.appendBaseUrl = function (baseUrl = '', oneOrMoreUrls) {
|
|
|
344
338
|
* @param {*} value value to set for key
|
|
345
339
|
*/
|
|
346
340
|
module.exports.replaceValueDeep = function replaceValueDeep(obj, key, value) {
|
|
347
|
-
if (!obj) return
|
|
341
|
+
if (!obj) return
|
|
348
342
|
|
|
349
343
|
if (obj instanceof Array) {
|
|
350
344
|
for (const i in obj) {
|
|
351
|
-
replaceValueDeep(obj[i], key, value)
|
|
345
|
+
replaceValueDeep(obj[i], key, value)
|
|
352
346
|
}
|
|
353
347
|
}
|
|
354
348
|
|
|
355
349
|
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
356
|
-
obj[key] = value
|
|
350
|
+
obj[key] = value
|
|
357
351
|
}
|
|
358
352
|
|
|
359
353
|
if (typeof obj === 'object' && obj !== null) {
|
|
360
|
-
const children = Object.values(obj)
|
|
354
|
+
const children = Object.values(obj)
|
|
361
355
|
for (const child of children) {
|
|
362
|
-
replaceValueDeep(child, key, value)
|
|
356
|
+
replaceValueDeep(child, key, value)
|
|
363
357
|
}
|
|
364
358
|
}
|
|
365
|
-
return obj
|
|
366
|
-
}
|
|
359
|
+
return obj
|
|
360
|
+
}
|
|
367
361
|
|
|
368
362
|
module.exports.ansiRegExp = function ({ onlyFirst = false } = {}) {
|
|
369
|
-
const pattern = [
|
|
370
|
-
'[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)',
|
|
371
|
-
'(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))',
|
|
372
|
-
].join('|');
|
|
363
|
+
const pattern = ['[\\u001B\\u009B][[\\]()#;?]*(?:(?:(?:[a-zA-Z\\d]*(?:;[-a-zA-Z\\d\\/#&.:=?%@~_]*)*)?\\u0007)', '(?:(?:\\d{1,4}(?:;\\d{0,4})*)?[\\dA-PR-TZcf-ntqry=><~]))'].join('|')
|
|
373
364
|
|
|
374
|
-
return new RegExp(pattern, onlyFirst ? undefined : 'g')
|
|
375
|
-
}
|
|
365
|
+
return new RegExp(pattern, onlyFirst ? undefined : 'g')
|
|
366
|
+
}
|
|
376
367
|
|
|
377
368
|
module.exports.tryOrDefault = function (fn, defaultValue) {
|
|
378
369
|
try {
|
|
379
|
-
return fn()
|
|
370
|
+
return fn()
|
|
380
371
|
} catch (_) {
|
|
381
|
-
return defaultValue
|
|
372
|
+
return defaultValue
|
|
382
373
|
}
|
|
383
|
-
}
|
|
374
|
+
}
|
|
384
375
|
|
|
385
376
|
function normalizeKeyReplacer(match, prefix, key, suffix, offset, string) {
|
|
386
377
|
if (typeof key !== 'string') {
|
|
387
|
-
return string
|
|
378
|
+
return string
|
|
388
379
|
}
|
|
389
|
-
const normalizedKey = key.charAt(0).toUpperCase() + key.substr(1).toLowerCase()
|
|
390
|
-
let position = ''
|
|
380
|
+
const normalizedKey = key.charAt(0).toUpperCase() + key.substr(1).toLowerCase()
|
|
381
|
+
let position = ''
|
|
391
382
|
if (typeof prefix === 'string') {
|
|
392
|
-
position = prefix
|
|
383
|
+
position = prefix
|
|
393
384
|
} else if (typeof suffix === 'string') {
|
|
394
|
-
position = suffix
|
|
385
|
+
position = suffix
|
|
395
386
|
}
|
|
396
|
-
return normalizedKey + position.charAt(0).toUpperCase() + position.substr(1).toLowerCase()
|
|
387
|
+
return normalizedKey + position.charAt(0).toUpperCase() + position.substr(1).toLowerCase()
|
|
397
388
|
}
|
|
398
389
|
|
|
399
390
|
/**
|
|
@@ -403,76 +394,93 @@ function normalizeKeyReplacer(match, prefix, key, suffix, offset, string) {
|
|
|
403
394
|
*/
|
|
404
395
|
module.exports.getNormalizedKeyAttributeValue = function (key) {
|
|
405
396
|
// Use operation modifier key based on operating system
|
|
406
|
-
key = key.replace(/(Ctrl|Control|Cmd|Command)[ _]?Or[ _]?(Ctrl|Control|Cmd|Command)/i, os.platform() === 'darwin' ? 'Meta' : 'Control')
|
|
397
|
+
key = key.replace(/(Ctrl|Control|Cmd|Command)[ _]?Or[ _]?(Ctrl|Control|Cmd|Command)/i, os.platform() === 'darwin' ? 'Meta' : 'Control')
|
|
407
398
|
// Selection of keys (https://www.w3.org/TR/uievents-key/#named-key-attribute-values)
|
|
408
399
|
// which can be written in various ways and should be normalized.
|
|
409
400
|
// For example 'LEFT ALT', 'ALT_Left', 'alt left' or 'LeftAlt' will be normalized as 'AltLeft'.
|
|
410
|
-
key = key.replace(/^\s*(?:(Down|Left|Right|Up)[ _]?)?(Arrow|Alt|Ctrl|Control|Cmd|Command|Meta|Option|OS|Page|Shift|Super)(?:[ _]?(Down|Left|Right|Up|Gr(?:aph)?))?\s*$/i, normalizeKeyReplacer)
|
|
401
|
+
key = key.replace(/^\s*(?:(Down|Left|Right|Up)[ _]?)?(Arrow|Alt|Ctrl|Control|Cmd|Command|Meta|Option|OS|Page|Shift|Super)(?:[ _]?(Down|Left|Right|Up|Gr(?:aph)?))?\s*$/i, normalizeKeyReplacer)
|
|
411
402
|
// Map alias to corresponding key value
|
|
412
|
-
key = key.replace(/^(Add|Divide|Decimal|Multiply|Subtract)$/, 'Numpad$1')
|
|
413
|
-
key = key.replace(/^AltGr$/, 'AltGraph')
|
|
414
|
-
key = key.replace(/^(Cmd|Command|Os|Super)/, 'Meta')
|
|
415
|
-
key = key.replace('Ctrl', 'Control')
|
|
416
|
-
key = key.replace('Option', 'Alt')
|
|
417
|
-
key = key.replace(/^(NumpadComma|Separator)$/, 'Comma')
|
|
418
|
-
return key
|
|
419
|
-
}
|
|
420
|
-
|
|
421
|
-
const modifierKeys = [
|
|
422
|
-
|
|
423
|
-
|
|
424
|
-
'Meta', 'MetaLeft', 'MetaRight',
|
|
425
|
-
'Shift', 'ShiftLeft', 'ShiftRight',
|
|
426
|
-
];
|
|
427
|
-
|
|
428
|
-
module.exports.modifierKeys = modifierKeys;
|
|
403
|
+
key = key.replace(/^(Add|Divide|Decimal|Multiply|Subtract)$/, 'Numpad$1')
|
|
404
|
+
key = key.replace(/^AltGr$/, 'AltGraph')
|
|
405
|
+
key = key.replace(/^(Cmd|Command|Os|Super)/, 'Meta')
|
|
406
|
+
key = key.replace('Ctrl', 'Control')
|
|
407
|
+
key = key.replace('Option', 'Alt')
|
|
408
|
+
key = key.replace(/^(NumpadComma|Separator)$/, 'Comma')
|
|
409
|
+
return key
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
const modifierKeys = ['Alt', 'AltGraph', 'AltLeft', 'AltRight', 'Control', 'ControlLeft', 'ControlRight', 'Meta', 'MetaLeft', 'MetaRight', 'Shift', 'ShiftLeft', 'ShiftRight']
|
|
413
|
+
|
|
414
|
+
module.exports.modifierKeys = modifierKeys
|
|
429
415
|
module.exports.isModifierKey = function (key) {
|
|
430
|
-
return modifierKeys.includes(key)
|
|
431
|
-
}
|
|
416
|
+
return modifierKeys.includes(key)
|
|
417
|
+
}
|
|
432
418
|
|
|
433
419
|
module.exports.requireWithFallback = function (...packages) {
|
|
434
420
|
const exists = function (pkg) {
|
|
435
421
|
try {
|
|
436
|
-
require.resolve(pkg)
|
|
422
|
+
require.resolve(pkg)
|
|
437
423
|
} catch (e) {
|
|
438
|
-
return false
|
|
424
|
+
return false
|
|
439
425
|
}
|
|
440
426
|
|
|
441
|
-
return true
|
|
442
|
-
}
|
|
427
|
+
return true
|
|
428
|
+
}
|
|
443
429
|
|
|
444
430
|
for (const pkg of packages) {
|
|
445
431
|
if (exists(pkg)) {
|
|
446
|
-
return require(pkg)
|
|
432
|
+
return require(pkg)
|
|
447
433
|
}
|
|
448
434
|
}
|
|
449
435
|
|
|
450
|
-
throw new Error(`Cannot find modules ${packages.join(',')}`)
|
|
451
|
-
}
|
|
436
|
+
throw new Error(`Cannot find modules ${packages.join(',')}`)
|
|
437
|
+
}
|
|
452
438
|
|
|
453
439
|
module.exports.isNotSet = function (obj) {
|
|
454
|
-
if (obj === null) return true
|
|
455
|
-
if (obj === undefined) return true
|
|
456
|
-
return false
|
|
457
|
-
}
|
|
440
|
+
if (obj === null) return true
|
|
441
|
+
if (obj === undefined) return true
|
|
442
|
+
return false
|
|
443
|
+
}
|
|
458
444
|
|
|
459
|
-
module.exports.emptyFolder = async
|
|
460
|
-
require('child_process').execSync(`rm -rf ${directoryPath}/*`)
|
|
461
|
-
}
|
|
445
|
+
module.exports.emptyFolder = async directoryPath => {
|
|
446
|
+
require('child_process').execSync(`rm -rf ${directoryPath}/*`)
|
|
447
|
+
}
|
|
462
448
|
|
|
463
|
-
module.exports.printObjectProperties =
|
|
449
|
+
module.exports.printObjectProperties = obj => {
|
|
464
450
|
if (typeof obj !== 'object' || obj === null) {
|
|
465
|
-
return obj
|
|
451
|
+
return obj
|
|
466
452
|
}
|
|
467
453
|
|
|
468
|
-
let result = ''
|
|
454
|
+
let result = ''
|
|
469
455
|
for (const [key, value] of Object.entries(obj)) {
|
|
470
|
-
result += `${key}: "${value}";
|
|
456
|
+
result += `${key}: "${value}"; `
|
|
471
457
|
}
|
|
472
458
|
|
|
473
|
-
return `{${result}}
|
|
474
|
-
}
|
|
459
|
+
return `{${result}}`
|
|
460
|
+
}
|
|
461
|
+
|
|
462
|
+
module.exports.normalizeSpacesInString = string => {
|
|
463
|
+
return string.replace(/\s+/g, ' ')
|
|
464
|
+
}
|
|
475
465
|
|
|
476
|
-
module.exports.
|
|
477
|
-
|
|
478
|
-
|
|
466
|
+
module.exports.humanizeFunction = function (fn) {
|
|
467
|
+
const fnStr = fn.toString().trim()
|
|
468
|
+
// Remove arrow function syntax, async, and parentheses
|
|
469
|
+
let simplified = fnStr
|
|
470
|
+
.replace(/^async\s*/, '')
|
|
471
|
+
.replace(/^\([^)]*\)\s*=>/, '')
|
|
472
|
+
.replace(/^function\s*\([^)]*\)/, '')
|
|
473
|
+
// Remove curly braces and any whitespace around them
|
|
474
|
+
.replace(/{\s*(.*)\s*}/, '$1')
|
|
475
|
+
// Remove return statement
|
|
476
|
+
.replace(/return\s+/, '')
|
|
477
|
+
// Remove trailing semicolon
|
|
478
|
+
.replace(/;$/, '')
|
|
479
|
+
.trim()
|
|
480
|
+
|
|
481
|
+
if (simplified.length > 100) {
|
|
482
|
+
simplified = simplified.slice(0, 97) + '...'
|
|
483
|
+
}
|
|
484
|
+
|
|
485
|
+
return simplified
|
|
486
|
+
}
|