codeceptjs 4.0.0-beta.4 → 4.0.0-beta.6.esm-aria
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 +89 -119
- package/bin/codecept.js +53 -54
- package/docs/webapi/clearCookie.mustache +1 -1
- package/lib/actor.js +70 -102
- package/lib/ai.js +131 -121
- package/lib/assert/empty.js +11 -12
- package/lib/assert/equal.js +16 -21
- package/lib/assert/error.js +2 -2
- package/lib/assert/include.js +11 -15
- package/lib/assert/throws.js +3 -5
- package/lib/assert/truth.js +10 -7
- package/lib/assert.js +18 -18
- package/lib/codecept.js +112 -101
- package/lib/colorUtils.js +48 -50
- package/lib/command/check.js +206 -0
- package/lib/command/configMigrate.js +13 -14
- package/lib/command/definitions.js +24 -36
- package/lib/command/dryRun.js +16 -16
- package/lib/command/generate.js +38 -39
- package/lib/command/gherkin/init.js +36 -38
- package/lib/command/gherkin/snippets.js +76 -74
- package/lib/command/gherkin/steps.js +21 -18
- package/lib/command/info.js +49 -15
- package/lib/command/init.js +41 -37
- package/lib/command/interactive.js +22 -13
- package/lib/command/list.js +11 -10
- package/lib/command/run-multiple/chunk.js +50 -47
- package/lib/command/run-multiple/collection.js +5 -5
- package/lib/command/run-multiple/run.js +3 -3
- package/lib/command/run-multiple.js +27 -47
- package/lib/command/run-rerun.js +6 -7
- package/lib/command/run-workers.js +15 -66
- package/lib/command/run.js +8 -8
- package/lib/command/utils.js +22 -21
- package/lib/command/workers/runTests.js +131 -241
- package/lib/config.js +111 -49
- package/lib/container.js +589 -244
- package/lib/data/context.js +16 -18
- package/lib/data/dataScenarioConfig.js +9 -9
- package/lib/data/dataTableArgument.js +7 -7
- package/lib/data/table.js +6 -12
- package/lib/effects.js +307 -0
- package/lib/els.js +160 -0
- package/lib/event.js +24 -19
- package/lib/globals.js +141 -0
- package/lib/heal.js +89 -81
- package/lib/helper/AI.js +3 -2
- package/lib/helper/ApiDataFactory.js +19 -19
- package/lib/helper/Appium.js +47 -51
- package/lib/helper/FileSystem.js +35 -15
- package/lib/helper/GraphQL.js +1 -1
- package/lib/helper/GraphQLDataFactory.js +4 -4
- package/lib/helper/JSONResponse.js +72 -45
- package/lib/helper/Mochawesome.js +14 -11
- package/lib/helper/Playwright.js +832 -434
- package/lib/helper/Puppeteer.js +393 -292
- package/lib/helper/REST.js +32 -27
- package/lib/helper/WebDriver.js +320 -219
- package/lib/helper/errors/ConnectionRefused.js +6 -6
- package/lib/helper/errors/ElementAssertion.js +11 -16
- package/lib/helper/errors/ElementNotFound.js +5 -9
- package/lib/helper/errors/RemoteBrowserConnectionRefused.js +5 -5
- package/lib/helper/extras/Console.js +11 -11
- package/lib/helper/extras/PlaywrightLocator.js +110 -0
- package/lib/helper/extras/PlaywrightPropEngine.js +18 -18
- package/lib/helper/extras/PlaywrightRestartOpts.js +23 -23
- package/lib/helper/extras/Popup.js +22 -22
- package/lib/helper/extras/React.js +29 -30
- package/lib/helper/network/actions.js +33 -48
- package/lib/helper/network/utils.js +76 -83
- package/lib/helper/scripts/blurElement.js +6 -6
- package/lib/helper/scripts/focusElement.js +6 -6
- package/lib/helper/scripts/highlightElement.js +9 -9
- package/lib/helper/scripts/isElementClickable.js +34 -34
- package/lib/helper.js +2 -1
- package/lib/history.js +23 -20
- package/lib/hooks.js +10 -10
- package/lib/html.js +90 -100
- package/lib/index.js +48 -21
- package/lib/listener/config.js +8 -9
- package/lib/listener/emptyRun.js +54 -0
- package/lib/listener/exit.js +10 -12
- package/lib/listener/{retry.js → globalRetry.js} +10 -10
- package/lib/listener/globalTimeout.js +166 -0
- package/lib/listener/helpers.js +43 -24
- package/lib/listener/mocha.js +4 -5
- package/lib/listener/result.js +11 -0
- package/lib/listener/steps.js +26 -23
- package/lib/listener/store.js +20 -0
- package/lib/locator.js +213 -192
- package/lib/mocha/asyncWrapper.js +264 -0
- package/lib/mocha/bdd.js +167 -0
- package/lib/mocha/cli.js +341 -0
- package/lib/mocha/factory.js +160 -0
- package/lib/{interfaces → mocha}/featureConfig.js +33 -13
- package/lib/{interfaces → mocha}/gherkin.js +75 -45
- package/lib/mocha/hooks.js +121 -0
- package/lib/mocha/index.js +21 -0
- package/lib/mocha/inject.js +46 -0
- package/lib/{interfaces → mocha}/scenarioConfig.js +32 -8
- package/lib/mocha/suite.js +89 -0
- package/lib/mocha/test.js +178 -0
- package/lib/mocha/types.d.ts +42 -0
- package/lib/mocha/ui.js +229 -0
- package/lib/output.js +86 -64
- package/lib/parser.js +44 -44
- package/lib/pause.js +160 -139
- package/lib/plugin/analyze.js +403 -0
- package/lib/plugin/{autoLogin.js → auth.js} +137 -43
- package/lib/plugin/autoDelay.js +19 -15
- package/lib/plugin/coverage.js +22 -27
- package/lib/plugin/customLocator.js +5 -5
- package/lib/plugin/customReporter.js +53 -0
- package/lib/plugin/heal.js +49 -17
- package/lib/plugin/pageInfo.js +140 -0
- package/lib/plugin/pauseOnFail.js +4 -3
- package/lib/plugin/retryFailedStep.js +60 -19
- package/lib/plugin/screenshotOnFail.js +80 -83
- package/lib/plugin/stepByStepReport.js +70 -31
- package/lib/plugin/stepTimeout.js +7 -13
- package/lib/plugin/subtitles.js +10 -9
- package/lib/recorder.js +167 -126
- package/lib/rerun.js +94 -50
- package/lib/result.js +161 -0
- package/lib/secret.js +18 -17
- package/lib/session.js +95 -89
- package/lib/step/base.js +239 -0
- package/lib/step/comment.js +10 -0
- package/lib/step/config.js +50 -0
- package/lib/step/func.js +46 -0
- package/lib/step/helper.js +50 -0
- package/lib/step/meta.js +99 -0
- package/lib/step/record.js +74 -0
- package/lib/step/retry.js +11 -0
- package/lib/step/section.js +55 -0
- package/lib/step.js +18 -332
- package/lib/steps.js +54 -0
- package/lib/store.js +37 -5
- package/lib/template/heal.js +2 -11
- package/lib/timeout.js +60 -0
- package/lib/transform.js +8 -8
- package/lib/translation.js +32 -18
- package/lib/utils.js +354 -250
- package/lib/workerStorage.js +16 -16
- package/lib/workers.js +366 -282
- package/package.json +107 -95
- package/translations/de-DE.js +5 -4
- package/translations/fr-FR.js +5 -4
- package/translations/index.js +23 -9
- package/translations/it-IT.js +5 -4
- package/translations/ja-JP.js +5 -4
- package/translations/nl-NL.js +76 -0
- package/translations/pl-PL.js +5 -4
- package/translations/pt-BR.js +5 -4
- package/translations/ru-RU.js +5 -4
- package/translations/utils.js +18 -0
- package/translations/zh-CN.js +5 -4
- package/translations/zh-TW.js +5 -4
- package/typings/index.d.ts +177 -186
- package/typings/promiseBasedTypes.d.ts +3573 -5941
- package/typings/types.d.ts +4042 -6370
- package/lib/cli.js +0 -256
- package/lib/helper/ExpectHelper.js +0 -391
- package/lib/helper/Nightmare.js +0 -1504
- package/lib/helper/Protractor.js +0 -1863
- package/lib/helper/SoftExpectHelper.js +0 -381
- package/lib/helper/TestCafe.js +0 -1414
- package/lib/helper/clientscripts/nightmare.js +0 -213
- package/lib/helper/extras/PlaywrightReactVueLocator.js +0 -43
- package/lib/helper/testcafe/testControllerHolder.js +0 -42
- package/lib/helper/testcafe/testcafe-utils.js +0 -62
- package/lib/interfaces/bdd.js +0 -81
- package/lib/listener/artifacts.js +0 -19
- package/lib/listener/timeout.js +0 -109
- package/lib/mochaFactory.js +0 -113
- package/lib/plugin/allure.js +0 -15
- package/lib/plugin/commentStep.js +0 -136
- package/lib/plugin/debugErrors.js +0 -67
- package/lib/plugin/eachElement.js +0 -127
- package/lib/plugin/fakerTransform.js +0 -49
- package/lib/plugin/retryTo.js +0 -127
- package/lib/plugin/selenoid.js +0 -384
- package/lib/plugin/standardActingHelpers.js +0 -3
- package/lib/plugin/tryTo.js +0 -115
- package/lib/plugin/wdio.js +0 -249
- package/lib/scenario.js +0 -224
- package/lib/ui.js +0 -236
- package/lib/within.js +0 -70
package/lib/utils.js
CHANGED
|
@@ -1,139 +1,134 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
1
|
+
import fs from 'fs'
|
|
2
|
+
import os from 'os'
|
|
3
|
+
import path from 'path'
|
|
4
|
+
import chalk from 'chalk'
|
|
5
|
+
import getFunctionArguments from 'fn-args'
|
|
6
|
+
import deepClone from 'lodash.clonedeep'
|
|
7
|
+
import merge from 'lodash.merge'
|
|
8
|
+
import { convertColorToRGBA, isColorProperty } from './colorUtils.js'
|
|
9
|
+
import Fuse from 'fuse.js'
|
|
10
|
+
import crypto from 'crypto'
|
|
11
|
+
import jsBeautify from 'js-beautify'
|
|
12
|
+
import childProcess from 'child_process'
|
|
13
|
+
import { createRequire } from 'module'
|
|
7
14
|
|
|
8
15
|
function deepMerge(target, source) {
|
|
9
|
-
|
|
10
|
-
return merge(target, source);
|
|
16
|
+
return merge(target, source)
|
|
11
17
|
}
|
|
12
18
|
|
|
13
|
-
|
|
14
|
-
return
|
|
15
|
-
|
|
16
|
-
};
|
|
19
|
+
export const genTestId = test => {
|
|
20
|
+
return clearString(crypto.createHash('sha256').update(test.fullTitle()).digest('base64').slice(0, -2))
|
|
21
|
+
}
|
|
17
22
|
|
|
18
|
-
|
|
23
|
+
export { deepMerge }
|
|
19
24
|
|
|
20
|
-
|
|
25
|
+
export { deepClone }
|
|
21
26
|
|
|
22
|
-
|
|
23
|
-
return fn.constructor.name === 'GeneratorFunction'
|
|
24
|
-
}
|
|
27
|
+
export const isGenerator = function (fn) {
|
|
28
|
+
return fn.constructor.name === 'GeneratorFunction'
|
|
29
|
+
}
|
|
25
30
|
|
|
26
|
-
const isFunction =
|
|
27
|
-
return typeof fn === 'function'
|
|
28
|
-
}
|
|
31
|
+
export const isFunction = function (fn) {
|
|
32
|
+
return typeof fn === 'function'
|
|
33
|
+
}
|
|
29
34
|
|
|
30
|
-
const isAsyncFunction =
|
|
31
|
-
if (!fn) return false
|
|
32
|
-
return fn[Symbol.toStringTag] === 'AsyncFunction'
|
|
33
|
-
}
|
|
35
|
+
export const isAsyncFunction = function (fn) {
|
|
36
|
+
if (!fn) return false
|
|
37
|
+
return fn[Symbol.toStringTag] === 'AsyncFunction'
|
|
38
|
+
}
|
|
34
39
|
|
|
35
|
-
|
|
36
|
-
return fs.existsSync(filePath)
|
|
37
|
-
}
|
|
40
|
+
export const fileExists = function (filePath) {
|
|
41
|
+
return fs.existsSync(filePath)
|
|
42
|
+
}
|
|
38
43
|
|
|
39
|
-
|
|
40
|
-
let filestat
|
|
44
|
+
export const isFile = function (filePath) {
|
|
45
|
+
let filestat
|
|
41
46
|
try {
|
|
42
|
-
filestat = fs.statSync(filePath)
|
|
47
|
+
filestat = fs.statSync(filePath)
|
|
43
48
|
} catch (err) {
|
|
44
|
-
if (err.code === 'ENOENT') return false
|
|
49
|
+
if (err.code === 'ENOENT') return false
|
|
45
50
|
}
|
|
46
|
-
if (!filestat) return false
|
|
47
|
-
return filestat.isFile()
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
if (fn.isSinonProxy) return []
|
|
52
|
-
return getFunctionArguments(fn)
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
return path.resolve(`${
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
|
|
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
|
-
];
|
|
51
|
+
if (!filestat) return false
|
|
52
|
+
return filestat.isFile()
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
export const getParamNames = function (fn) {
|
|
56
|
+
if (fn.isSinonProxy) return []
|
|
57
|
+
return getFunctionArguments(fn)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export const installedLocally = function () {
|
|
61
|
+
return path.resolve(`${new URL(import.meta.url).pathname}/../../`).indexOf(process.cwd()) === 0
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
export const methodsOfObject = function (obj, className) {
|
|
65
|
+
const methods = []
|
|
66
|
+
|
|
67
|
+
const standard = ['constructor', 'toString', 'toLocaleString', 'valueOf', 'hasOwnProperty', 'bind', 'apply', 'call', 'isPrototypeOf', 'propertyIsEnumerable']
|
|
74
68
|
|
|
75
69
|
function pushToMethods(prop) {
|
|
76
70
|
try {
|
|
77
|
-
if (!isFunction(obj[prop]) && !isAsyncFunction(obj[prop])) return
|
|
78
|
-
} catch (err) {
|
|
79
|
-
|
|
71
|
+
if (!isFunction(obj[prop]) && !isAsyncFunction(obj[prop])) return
|
|
72
|
+
} catch (err) {
|
|
73
|
+
// can't access property
|
|
74
|
+
return
|
|
80
75
|
}
|
|
81
|
-
if (standard.indexOf(prop) >= 0) return
|
|
82
|
-
if (prop.indexOf('_') === 0) return
|
|
83
|
-
methods.push(prop)
|
|
76
|
+
if (standard.indexOf(prop) >= 0) return
|
|
77
|
+
if (prop.indexOf('_') === 0) return
|
|
78
|
+
methods.push(prop)
|
|
84
79
|
}
|
|
85
80
|
|
|
86
81
|
while (obj.constructor.name !== className) {
|
|
87
|
-
Object.getOwnPropertyNames(obj).forEach(pushToMethods)
|
|
88
|
-
obj = Object.getPrototypeOf(obj)
|
|
82
|
+
Object.getOwnPropertyNames(obj).forEach(pushToMethods)
|
|
83
|
+
obj = Object.getPrototypeOf(obj)
|
|
89
84
|
|
|
90
|
-
if (!obj || !obj.constructor) break
|
|
85
|
+
if (!obj || !obj.constructor) break
|
|
91
86
|
}
|
|
92
|
-
return methods
|
|
93
|
-
}
|
|
87
|
+
return methods
|
|
88
|
+
}
|
|
94
89
|
|
|
95
|
-
|
|
90
|
+
export const template = function (template, data) {
|
|
96
91
|
return template.replace(/{{([^{}]*)}}/g, (a, b) => {
|
|
97
|
-
const r = data[b]
|
|
98
|
-
if (r === undefined) return ''
|
|
99
|
-
return r.toString()
|
|
100
|
-
})
|
|
101
|
-
}
|
|
92
|
+
const r = data[b]
|
|
93
|
+
if (r === undefined) return ''
|
|
94
|
+
return r.toString()
|
|
95
|
+
})
|
|
96
|
+
}
|
|
102
97
|
|
|
103
98
|
/**
|
|
104
99
|
* Make first char uppercase.
|
|
105
100
|
* @param {string} str
|
|
106
|
-
* @returns {string}
|
|
101
|
+
* @returns {string | undefined}
|
|
107
102
|
*/
|
|
108
|
-
|
|
109
|
-
return str.charAt(0).toUpperCase() + str.substr(1)
|
|
110
|
-
}
|
|
103
|
+
export const ucfirst = function (str) {
|
|
104
|
+
if (str) return str.charAt(0).toUpperCase() + str.substr(1)
|
|
105
|
+
}
|
|
111
106
|
|
|
112
107
|
/**
|
|
113
108
|
* Make first char lowercase.
|
|
114
109
|
* @param {string} str
|
|
115
|
-
* @returns {string}
|
|
110
|
+
* @returns {string | undefined}
|
|
116
111
|
*/
|
|
117
|
-
|
|
118
|
-
return str.charAt(0).toLowerCase() + str.substr(1)
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
let i
|
|
123
|
-
let j
|
|
124
|
-
const tmp = []
|
|
112
|
+
export const lcfirst = function (str) {
|
|
113
|
+
if (str) return str.charAt(0).toLowerCase() + str.substr(1)
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
export const chunkArray = function (arr, chunk) {
|
|
117
|
+
let i
|
|
118
|
+
let j
|
|
119
|
+
const tmp = []
|
|
125
120
|
for (i = 0, j = arr.length; i < j; i += chunk) {
|
|
126
|
-
tmp.push(arr.slice(i, i + chunk))
|
|
121
|
+
tmp.push(arr.slice(i, i + chunk))
|
|
127
122
|
}
|
|
128
|
-
return tmp
|
|
129
|
-
}
|
|
123
|
+
return tmp
|
|
124
|
+
}
|
|
130
125
|
|
|
131
|
-
|
|
132
|
-
if (!str) return ''
|
|
126
|
+
export const clearString = function (str) {
|
|
127
|
+
if (!str) return ''
|
|
133
128
|
/* Replace forbidden symbols in string
|
|
134
129
|
*/
|
|
135
130
|
if (str.endsWith('.')) {
|
|
136
|
-
str = str.slice(0, -1)
|
|
131
|
+
str = str.slice(0, -1)
|
|
137
132
|
}
|
|
138
133
|
return str
|
|
139
134
|
.replace(/ /g, '_')
|
|
@@ -146,26 +141,29 @@ module.exports.clearString = function (str) {
|
|
|
146
141
|
.replace(/\|/g, '_')
|
|
147
142
|
.replace(/\?/g, '.')
|
|
148
143
|
.replace(/\*/g, '^')
|
|
149
|
-
.replace(/'/g, '')
|
|
150
|
-
}
|
|
144
|
+
.replace(/'/g, '')
|
|
145
|
+
}
|
|
151
146
|
|
|
152
|
-
|
|
147
|
+
export const decodeUrl = function (url) {
|
|
153
148
|
/* Replace forbidden symbols in string
|
|
154
149
|
*/
|
|
155
|
-
return decodeURIComponent(decodeURIComponent(decodeURIComponent(url)))
|
|
156
|
-
}
|
|
150
|
+
return decodeURIComponent(decodeURIComponent(decodeURIComponent(url)))
|
|
151
|
+
}
|
|
157
152
|
|
|
158
|
-
|
|
153
|
+
export const xpathLocator = {
|
|
159
154
|
/**
|
|
160
155
|
* @param {string} string
|
|
161
156
|
* @returns {string}
|
|
162
157
|
*/
|
|
163
|
-
literal:
|
|
158
|
+
literal: string => {
|
|
164
159
|
if (string.indexOf("'") > -1) {
|
|
165
|
-
string = string
|
|
166
|
-
|
|
160
|
+
string = string
|
|
161
|
+
.split("'", -1)
|
|
162
|
+
.map(substr => `'${substr}'`)
|
|
163
|
+
.join(',"\'",')
|
|
164
|
+
return `concat(${string})`
|
|
167
165
|
}
|
|
168
|
-
return `'${string}'
|
|
166
|
+
return `'${string}'`
|
|
169
167
|
},
|
|
170
168
|
|
|
171
169
|
/**
|
|
@@ -174,55 +172,52 @@ module.exports.xpathLocator = {
|
|
|
174
172
|
* @returns {string}
|
|
175
173
|
*/
|
|
176
174
|
combine: locators => locators.join(' | '),
|
|
177
|
-
}
|
|
178
|
-
|
|
179
|
-
module.exports.test = {
|
|
175
|
+
}
|
|
180
176
|
|
|
177
|
+
export const test = {
|
|
181
178
|
grepLines(array, startString, endString) {
|
|
182
|
-
let startIndex = 0
|
|
183
|
-
let endIndex
|
|
179
|
+
let startIndex = 0
|
|
180
|
+
let endIndex
|
|
184
181
|
array.every((elem, index) => {
|
|
185
182
|
if (elem === startString) {
|
|
186
|
-
startIndex = index
|
|
187
|
-
return true
|
|
183
|
+
startIndex = index
|
|
184
|
+
return true
|
|
188
185
|
}
|
|
189
186
|
if (elem === endString) {
|
|
190
|
-
endIndex = index
|
|
191
|
-
return false
|
|
187
|
+
endIndex = index
|
|
188
|
+
return false
|
|
192
189
|
}
|
|
193
|
-
return true
|
|
194
|
-
})
|
|
195
|
-
return array.slice(startIndex + 1, endIndex)
|
|
190
|
+
return true
|
|
191
|
+
})
|
|
192
|
+
return array.slice(startIndex + 1, endIndex)
|
|
196
193
|
},
|
|
197
194
|
|
|
198
195
|
submittedData(dataFile) {
|
|
199
196
|
return function (key) {
|
|
200
197
|
if (!fs.existsSync(dataFile)) {
|
|
201
|
-
const waitTill = new Date(new Date().getTime() + 1 * 1000)
|
|
202
|
-
while (waitTill > new Date()) {}
|
|
198
|
+
const waitTill = new Date(new Date().getTime() + 1 * 1000) // wait for one sec for file to be created
|
|
199
|
+
while (waitTill > new Date()) {}
|
|
203
200
|
}
|
|
204
201
|
if (!fs.existsSync(dataFile)) {
|
|
205
|
-
throw new Error('Data file was not created in time')
|
|
202
|
+
throw new Error('Data file was not created in time')
|
|
206
203
|
}
|
|
207
|
-
const data = JSON.parse(fs.readFileSync(dataFile, 'utf8'))
|
|
204
|
+
const data = JSON.parse(fs.readFileSync(dataFile, 'utf8'))
|
|
208
205
|
if (key) {
|
|
209
|
-
return data.form[key]
|
|
206
|
+
return data.form[key]
|
|
210
207
|
}
|
|
211
|
-
return data
|
|
212
|
-
}
|
|
208
|
+
return data
|
|
209
|
+
}
|
|
213
210
|
},
|
|
211
|
+
}
|
|
214
212
|
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
function toCamelCase(name) {
|
|
213
|
+
export const toCamelCase = function (name) {
|
|
218
214
|
if (typeof name !== 'string') {
|
|
219
|
-
return name
|
|
215
|
+
return name
|
|
220
216
|
}
|
|
221
217
|
return name.replace(/-(\w)/gi, (_word, letter) => {
|
|
222
|
-
return letter.toUpperCase()
|
|
223
|
-
})
|
|
218
|
+
return letter.toUpperCase()
|
|
219
|
+
})
|
|
224
220
|
}
|
|
225
|
-
module.exports.toCamelCase = toCamelCase;
|
|
226
221
|
|
|
227
222
|
function convertFontWeightToNumber(name) {
|
|
228
223
|
const fontWeightPatterns = [
|
|
@@ -235,106 +230,110 @@ function convertFontWeightToNumber(name) {
|
|
|
235
230
|
{ num: 700, pattern: /^Bold$/i },
|
|
236
231
|
{ num: 800, pattern: /^(Extra|Ultra)-?bold$/i },
|
|
237
232
|
{ num: 900, pattern: /^(Black|Heavy)$/i },
|
|
238
|
-
]
|
|
233
|
+
]
|
|
239
234
|
|
|
240
235
|
if (/^[1-9]00$/.test(name)) {
|
|
241
|
-
return Number(name)
|
|
236
|
+
return Number(name)
|
|
242
237
|
}
|
|
243
238
|
|
|
244
|
-
const matches = fontWeightPatterns.filter(fontWeight => fontWeight.pattern.test(name))
|
|
239
|
+
const matches = fontWeightPatterns.filter(fontWeight => fontWeight.pattern.test(name))
|
|
245
240
|
|
|
246
241
|
if (matches.length) {
|
|
247
|
-
return String(matches[0].num)
|
|
242
|
+
return String(matches[0].num)
|
|
248
243
|
}
|
|
249
|
-
return name
|
|
244
|
+
return name
|
|
250
245
|
}
|
|
251
246
|
|
|
252
247
|
function isFontWeightProperty(prop) {
|
|
253
|
-
return prop === 'fontWeight'
|
|
248
|
+
return prop === 'fontWeight'
|
|
254
249
|
}
|
|
255
250
|
|
|
256
|
-
|
|
257
|
-
const output = {}
|
|
258
|
-
Object.keys(props).forEach(
|
|
259
|
-
const keyCamel = toCamelCase(key)
|
|
251
|
+
export const convertCssPropertiesToCamelCase = function (props) {
|
|
252
|
+
const output = {}
|
|
253
|
+
Object.keys(props).forEach(key => {
|
|
254
|
+
const keyCamel = toCamelCase(key)
|
|
260
255
|
|
|
261
256
|
if (isFontWeightProperty(keyCamel)) {
|
|
262
|
-
output[keyCamel] = convertFontWeightToNumber(props[key])
|
|
257
|
+
output[keyCamel] = convertFontWeightToNumber(props[key])
|
|
263
258
|
} else if (isColorProperty(keyCamel)) {
|
|
264
|
-
output[keyCamel] = convertColorToRGBA(props[key])
|
|
259
|
+
output[keyCamel] = convertColorToRGBA(props[key])
|
|
265
260
|
} else {
|
|
266
|
-
output[keyCamel] = props[key]
|
|
261
|
+
output[keyCamel] = props[key]
|
|
267
262
|
}
|
|
268
|
-
})
|
|
269
|
-
return output
|
|
270
|
-
}
|
|
263
|
+
})
|
|
264
|
+
return output
|
|
265
|
+
}
|
|
271
266
|
|
|
272
|
-
|
|
267
|
+
export const deleteDir = function (dir_path) {
|
|
273
268
|
if (fs.existsSync(dir_path)) {
|
|
274
269
|
fs.readdirSync(dir_path).forEach(function (entry) {
|
|
275
|
-
const entry_path = path.join(dir_path, entry)
|
|
270
|
+
const entry_path = path.join(dir_path, entry)
|
|
276
271
|
if (fs.lstatSync(entry_path).isDirectory()) {
|
|
277
|
-
|
|
272
|
+
deleteDir(entry_path)
|
|
278
273
|
} else {
|
|
279
|
-
fs.unlinkSync(entry_path)
|
|
274
|
+
fs.unlinkSync(entry_path)
|
|
280
275
|
}
|
|
281
|
-
})
|
|
282
|
-
fs.rmdirSync(dir_path)
|
|
276
|
+
})
|
|
277
|
+
fs.rmdirSync(dir_path)
|
|
283
278
|
}
|
|
284
|
-
}
|
|
279
|
+
}
|
|
285
280
|
|
|
286
281
|
/**
|
|
287
282
|
* Returns absolute filename to save screenshot.
|
|
288
283
|
* @param fileName {string} - filename.
|
|
289
284
|
*/
|
|
290
|
-
|
|
291
|
-
const fileSep = path.sep
|
|
285
|
+
export const screenshotOutputFolder = function (fileName) {
|
|
286
|
+
const fileSep = path.sep
|
|
292
287
|
|
|
293
288
|
if (!fileName.includes(fileSep) || fileName.includes('record_')) {
|
|
294
|
-
return path.resolve(global.output_dir, fileName)
|
|
289
|
+
return path.resolve(global.output_dir, fileName)
|
|
295
290
|
}
|
|
296
|
-
return path.resolve(global.codecept_dir, fileName)
|
|
297
|
-
}
|
|
291
|
+
return path.resolve(global.codecept_dir, fileName)
|
|
292
|
+
}
|
|
298
293
|
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
294
|
+
export const relativeDir = function (fileName) {
|
|
295
|
+
return fileName.replace(global.codecept_dir, '').replace(/^\//, '')
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
export const beautify = function (code) {
|
|
299
|
+
const format = jsBeautify.js
|
|
300
|
+
return format(code, { indent_size: 2, space_in_empty_paren: true })
|
|
301
|
+
}
|
|
303
302
|
|
|
304
303
|
function shouldAppendBaseUrl(url) {
|
|
305
|
-
return !/^\w+\:\/\//.test(url)
|
|
304
|
+
return !/^\w+\:\/\//.test(url)
|
|
306
305
|
}
|
|
307
306
|
|
|
308
307
|
function trimUrl(url) {
|
|
309
|
-
const firstChar = url.substr(1)
|
|
308
|
+
const firstChar = url.substr(1)
|
|
310
309
|
if (firstChar === '/') {
|
|
311
|
-
url = url.slice(1)
|
|
310
|
+
url = url.slice(1)
|
|
312
311
|
}
|
|
313
|
-
return url
|
|
312
|
+
return url
|
|
314
313
|
}
|
|
315
314
|
|
|
316
315
|
function joinUrl(baseUrl, url) {
|
|
317
|
-
return shouldAppendBaseUrl(url) ? `${baseUrl}/${trimUrl(url)}` : url
|
|
316
|
+
return shouldAppendBaseUrl(url) ? `${baseUrl}/${trimUrl(url)}` : url
|
|
318
317
|
}
|
|
319
318
|
|
|
320
|
-
|
|
319
|
+
export const appendBaseUrl = function (baseUrl = '', oneOrMoreUrls) {
|
|
321
320
|
if (typeof baseUrl !== 'string') {
|
|
322
|
-
throw new Error(`Invalid value for baseUrl: ${baseUrl}`)
|
|
321
|
+
throw new Error(`Invalid value for baseUrl: ${baseUrl}`)
|
|
323
322
|
}
|
|
324
323
|
if (!(typeof oneOrMoreUrls === 'string' || Array.isArray(oneOrMoreUrls))) {
|
|
325
|
-
throw new Error(`Expected type of Urls is 'string' or 'array', Found '${typeof oneOrMoreUrls}'.`)
|
|
324
|
+
throw new Error(`Expected type of Urls is 'string' or 'array', Found '${typeof oneOrMoreUrls}'.`)
|
|
326
325
|
}
|
|
327
326
|
// Remove '/' if it's at the end of baseUrl
|
|
328
|
-
const lastChar = baseUrl.substr(-1)
|
|
327
|
+
const lastChar = baseUrl.substr(-1)
|
|
329
328
|
if (lastChar === '/') {
|
|
330
|
-
baseUrl = baseUrl.slice(0, -1)
|
|
329
|
+
baseUrl = baseUrl.slice(0, -1)
|
|
331
330
|
}
|
|
332
331
|
|
|
333
332
|
if (!Array.isArray(oneOrMoreUrls)) {
|
|
334
|
-
return joinUrl(baseUrl, oneOrMoreUrls)
|
|
333
|
+
return joinUrl(baseUrl, oneOrMoreUrls)
|
|
335
334
|
}
|
|
336
|
-
return oneOrMoreUrls.map(url => joinUrl(baseUrl, url))
|
|
337
|
-
}
|
|
335
|
+
return oneOrMoreUrls.map(url => joinUrl(baseUrl, url))
|
|
336
|
+
}
|
|
338
337
|
|
|
339
338
|
/**
|
|
340
339
|
* Recursively search key in object and replace it's value.
|
|
@@ -343,57 +342,54 @@ module.exports.appendBaseUrl = function (baseUrl = '', oneOrMoreUrls) {
|
|
|
343
342
|
* @param {string} key key to search
|
|
344
343
|
* @param {*} value value to set for key
|
|
345
344
|
*/
|
|
346
|
-
|
|
347
|
-
if (!obj) return
|
|
345
|
+
export const replaceValueDeep = function replaceValueDeep(obj, key, value) {
|
|
346
|
+
if (!obj) return
|
|
348
347
|
|
|
349
348
|
if (obj instanceof Array) {
|
|
350
349
|
for (const i in obj) {
|
|
351
|
-
replaceValueDeep(obj[i], key, value)
|
|
350
|
+
replaceValueDeep(obj[i], key, value)
|
|
352
351
|
}
|
|
353
352
|
}
|
|
354
353
|
|
|
355
354
|
if (Object.prototype.hasOwnProperty.call(obj, key)) {
|
|
356
|
-
obj[key] = value
|
|
355
|
+
obj[key] = value
|
|
357
356
|
}
|
|
358
357
|
|
|
359
358
|
if (typeof obj === 'object' && obj !== null) {
|
|
360
|
-
const children = Object.values(obj)
|
|
359
|
+
const children = Object.values(obj)
|
|
361
360
|
for (const child of children) {
|
|
362
|
-
replaceValueDeep(child, key, value)
|
|
361
|
+
replaceValueDeep(child, key, value)
|
|
363
362
|
}
|
|
364
363
|
}
|
|
365
|
-
return obj
|
|
366
|
-
}
|
|
364
|
+
return obj
|
|
365
|
+
}
|
|
367
366
|
|
|
368
|
-
|
|
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('|');
|
|
367
|
+
export const ansiRegExp = function ({ onlyFirst = false } = {}) {
|
|
368
|
+
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
369
|
|
|
374
|
-
return new RegExp(pattern, onlyFirst ? undefined : 'g')
|
|
375
|
-
}
|
|
370
|
+
return new RegExp(pattern, onlyFirst ? undefined : 'g')
|
|
371
|
+
}
|
|
376
372
|
|
|
377
|
-
|
|
373
|
+
export const tryOrDefault = function (fn, defaultValue) {
|
|
378
374
|
try {
|
|
379
|
-
return fn()
|
|
375
|
+
return fn()
|
|
380
376
|
} catch (_) {
|
|
381
|
-
return defaultValue
|
|
377
|
+
return defaultValue
|
|
382
378
|
}
|
|
383
|
-
}
|
|
379
|
+
}
|
|
384
380
|
|
|
385
381
|
function normalizeKeyReplacer(match, prefix, key, suffix, offset, string) {
|
|
386
382
|
if (typeof key !== 'string') {
|
|
387
|
-
return string
|
|
383
|
+
return string
|
|
388
384
|
}
|
|
389
|
-
const normalizedKey = key.charAt(0).toUpperCase() + key.substr(1).toLowerCase()
|
|
390
|
-
let position = ''
|
|
385
|
+
const normalizedKey = key.charAt(0).toUpperCase() + key.substr(1).toLowerCase()
|
|
386
|
+
let position = ''
|
|
391
387
|
if (typeof prefix === 'string') {
|
|
392
|
-
position = prefix
|
|
388
|
+
position = prefix
|
|
393
389
|
} else if (typeof suffix === 'string') {
|
|
394
|
-
position = suffix
|
|
390
|
+
position = suffix
|
|
395
391
|
}
|
|
396
|
-
return normalizedKey + position.charAt(0).toUpperCase() + position.substr(1).toLowerCase()
|
|
392
|
+
return normalizedKey + position.charAt(0).toUpperCase() + position.substr(1).toLowerCase()
|
|
397
393
|
}
|
|
398
394
|
|
|
399
395
|
/**
|
|
@@ -401,78 +397,186 @@ function normalizeKeyReplacer(match, prefix, key, suffix, offset, string) {
|
|
|
401
397
|
* @param {string} key
|
|
402
398
|
* @returns {string}
|
|
403
399
|
*/
|
|
404
|
-
|
|
400
|
+
export const getNormalizedKeyAttributeValue = function (key) {
|
|
405
401
|
// 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')
|
|
402
|
+
key = key.replace(/(Ctrl|Control|Cmd|Command)[ _]?Or[ _]?(Ctrl|Control|Cmd|Command)/i, os.platform() === 'darwin' ? 'Meta' : 'Control')
|
|
407
403
|
// Selection of keys (https://www.w3.org/TR/uievents-key/#named-key-attribute-values)
|
|
408
404
|
// which can be written in various ways and should be normalized.
|
|
409
405
|
// 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)
|
|
406
|
+
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
407
|
// 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
|
-
|
|
425
|
-
|
|
426
|
-
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
module.exports.isModifierKey = function (key) {
|
|
430
|
-
return modifierKeys.includes(key);
|
|
431
|
-
};
|
|
432
|
-
|
|
433
|
-
module.exports.requireWithFallback = function (...packages) {
|
|
408
|
+
key = key.replace(/^(Add|Divide|Decimal|Multiply|Subtract)$/, 'Numpad$1')
|
|
409
|
+
key = key.replace(/^AltGr$/, 'AltGraph')
|
|
410
|
+
key = key.replace(/^(Cmd|Command|Os|Super)/, 'Meta')
|
|
411
|
+
key = key.replace('Ctrl', 'Control')
|
|
412
|
+
key = key.replace('Option', 'Alt')
|
|
413
|
+
key = key.replace(/^(NumpadComma|Separator)$/, 'Comma')
|
|
414
|
+
return key
|
|
415
|
+
}
|
|
416
|
+
|
|
417
|
+
export const modifierKeys = ['Alt', 'AltGraph', 'AltLeft', 'AltRight', 'Control', 'ControlLeft', 'ControlRight', 'Meta', 'MetaLeft', 'MetaRight', 'Shift', 'ShiftLeft', 'ShiftRight']
|
|
418
|
+
export const isModifierKey = function (key) {
|
|
419
|
+
return modifierKeys.includes(key)
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
export const requireWithFallback = function (...packages) {
|
|
423
|
+
const require = createRequire(import.meta.url)
|
|
424
|
+
|
|
434
425
|
const exists = function (pkg) {
|
|
435
426
|
try {
|
|
436
|
-
require.resolve(pkg)
|
|
427
|
+
require.resolve(pkg)
|
|
437
428
|
} catch (e) {
|
|
438
|
-
return false
|
|
429
|
+
return false
|
|
439
430
|
}
|
|
440
431
|
|
|
441
|
-
return true
|
|
442
|
-
}
|
|
432
|
+
return true
|
|
433
|
+
}
|
|
443
434
|
|
|
444
435
|
for (const pkg of packages) {
|
|
445
436
|
if (exists(pkg)) {
|
|
446
|
-
return require(pkg)
|
|
437
|
+
return require(pkg)
|
|
447
438
|
}
|
|
448
439
|
}
|
|
449
440
|
|
|
450
|
-
throw new Error(`Cannot find modules ${packages.join(',')}`)
|
|
451
|
-
}
|
|
441
|
+
throw new Error(`Cannot find modules ${packages.join(',')}`)
|
|
442
|
+
}
|
|
452
443
|
|
|
453
|
-
|
|
454
|
-
if (obj === null) return true
|
|
455
|
-
if (obj === undefined) return true
|
|
456
|
-
return false
|
|
457
|
-
}
|
|
444
|
+
export const isNotSet = function (obj) {
|
|
445
|
+
if (obj === null) return true
|
|
446
|
+
if (obj === undefined) return true
|
|
447
|
+
return false
|
|
448
|
+
}
|
|
458
449
|
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
}
|
|
450
|
+
export const emptyFolder = async directoryPath => {
|
|
451
|
+
childProcess.execSync(`rm -rf ${directoryPath}/*`)
|
|
452
|
+
}
|
|
462
453
|
|
|
463
|
-
|
|
454
|
+
export const printObjectProperties = obj => {
|
|
464
455
|
if (typeof obj !== 'object' || obj === null) {
|
|
465
|
-
return obj
|
|
456
|
+
return obj
|
|
466
457
|
}
|
|
467
458
|
|
|
468
|
-
let result = ''
|
|
459
|
+
let result = ''
|
|
469
460
|
for (const [key, value] of Object.entries(obj)) {
|
|
470
|
-
result += `${key}: "${value}";
|
|
461
|
+
result += `${key}: "${value}"; `
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
return `{${result}}`
|
|
465
|
+
}
|
|
466
|
+
|
|
467
|
+
export const normalizeSpacesInString = string => {
|
|
468
|
+
return string.replace(/\s+/g, ' ')
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
export const humanizeFunction = function (fn) {
|
|
472
|
+
const fnStr = fn.toString().trim()
|
|
473
|
+
// Remove arrow function syntax, async, and parentheses
|
|
474
|
+
let simplified = fnStr
|
|
475
|
+
.replace(/^async\s*/, '')
|
|
476
|
+
.replace(/^\([^)]*\)\s*=>/, '')
|
|
477
|
+
.replace(/^function\s*\([^)]*\)/, '')
|
|
478
|
+
// Remove curly braces and any whitespace around them
|
|
479
|
+
.replace(/{\s*(.*)\s*}/, '$1')
|
|
480
|
+
// Remove return statement
|
|
481
|
+
.replace(/return\s+/, '')
|
|
482
|
+
// Remove trailing semicolon
|
|
483
|
+
.replace(/;$/, '')
|
|
484
|
+
.trim()
|
|
485
|
+
|
|
486
|
+
if (simplified.length > 100) {
|
|
487
|
+
simplified = simplified.slice(0, 97) + '...'
|
|
488
|
+
}
|
|
489
|
+
|
|
490
|
+
return simplified
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
/**
|
|
494
|
+
* Searches through a given data source using the Fuse.js library for fuzzy searching.
|
|
495
|
+
*
|
|
496
|
+
* @function searchWithFusejs
|
|
497
|
+
* @param {Array|Object} source - The data source to search through. This can be an array of objects or strings.
|
|
498
|
+
* @param {string} searchString - The search query string to match against the source.
|
|
499
|
+
* @param {Object} [opts] - Optional configuration object for Fuse.js.
|
|
500
|
+
* @param {boolean} [opts.includeScore=true] - Whether to include the score of the match in the results.
|
|
501
|
+
* @param {number} [opts.threshold=0.6] - Determines the match threshold; lower values mean stricter matching.
|
|
502
|
+
* @param {boolean} [opts.caseSensitive=false] - Whether the search should be case-sensitive.
|
|
503
|
+
* @param {number} [opts.distance=100] - Determines how far apart the search term is allowed to be from the target.
|
|
504
|
+
* @param {number} [opts.maxPatternLength=32] - The maximum length of the search pattern. Patterns longer than this are ignored.
|
|
505
|
+
* @param {boolean} [opts.ignoreLocation=false] - Whether the location of the match is ignored when scoring.
|
|
506
|
+
* @param {boolean} [opts.ignoreFieldNorm=false] - When true, the field's length is not considered when scoring.
|
|
507
|
+
* @param {Array<string>} [opts.keys=[]] - List of keys to search in the objects of the source array.
|
|
508
|
+
* @param {boolean} [opts.shouldSort=true] - Whether the results should be sorted by score.
|
|
509
|
+
* @param {string} [opts.sortFn] - A custom sorting function for sorting results.
|
|
510
|
+
* @param {number} [opts.minMatchCharLength=1] - The minimum number of characters that must match.
|
|
511
|
+
* @param {boolean} [opts.useExtendedSearch=false] - Enables extended search capabilities.
|
|
512
|
+
*
|
|
513
|
+
* @returns {Array<Object>} - An array of search results. Each result contains an item and, if `includeScore` is true, a score.
|
|
514
|
+
*
|
|
515
|
+
* @example
|
|
516
|
+
* const data = [
|
|
517
|
+
* { title: "Old Man's War", author: "John Scalzi" },
|
|
518
|
+
* { title: "The Lock Artist", author: "Steve Hamilton" },
|
|
519
|
+
* ];
|
|
520
|
+
*
|
|
521
|
+
* const options = {
|
|
522
|
+
* keys: ['title', 'author'],
|
|
523
|
+
* includeScore: true,
|
|
524
|
+
* threshold: 0.4,
|
|
525
|
+
* caseSensitive: false,
|
|
526
|
+
* distance: 50,
|
|
527
|
+
* ignoreLocation: true,
|
|
528
|
+
* };
|
|
529
|
+
*
|
|
530
|
+
* const results = searchWithFusejs(data, 'lock', options);
|
|
531
|
+
* console.log(results);
|
|
532
|
+
*/
|
|
533
|
+
export const searchWithFusejs = function (source, searchString, opts) {
|
|
534
|
+
const fuse = new Fuse(source, opts)
|
|
535
|
+
|
|
536
|
+
return fuse.search(searchString)
|
|
537
|
+
}
|
|
538
|
+
|
|
539
|
+
export const humanizeString = function (string) {
|
|
540
|
+
// split strings by words, then make them all lowercase
|
|
541
|
+
const _result = string
|
|
542
|
+
.replace(/([a-z](?=[A-Z]))/g, '$1 ')
|
|
543
|
+
.split(' ')
|
|
544
|
+
.map(word => word.toLowerCase())
|
|
545
|
+
|
|
546
|
+
_result[0] = _result[0] === 'i' ? ucfirst(_result[0]) : _result[0]
|
|
547
|
+
return _result.join(' ').trim()
|
|
548
|
+
}
|
|
549
|
+
|
|
550
|
+
export const serializeError = function (error) {
|
|
551
|
+
if (error) {
|
|
552
|
+
const { stack, uncaught, message, actual, expected } = error
|
|
553
|
+
return { stack, uncaught, message, actual, expected }
|
|
471
554
|
}
|
|
555
|
+
return null
|
|
556
|
+
}
|
|
472
557
|
|
|
473
|
-
|
|
474
|
-
|
|
558
|
+
export const base64EncodeFile = function (filePath) {
|
|
559
|
+
return Buffer.from(fs.readFileSync(filePath)).toString('base64')
|
|
560
|
+
}
|
|
475
561
|
|
|
476
|
-
|
|
477
|
-
return
|
|
478
|
-
|
|
562
|
+
export const markdownToAnsi = function (markdown) {
|
|
563
|
+
return (
|
|
564
|
+
markdown
|
|
565
|
+
// Headers (# Text) - make blue and bold
|
|
566
|
+
.replace(/^(#{1,6})\s+(.+)$/gm, (_, hashes, text) => {
|
|
567
|
+
return chalk.bold.blue(`${hashes} ${text}`)
|
|
568
|
+
})
|
|
569
|
+
// Bullet points - replace with yellow bullet character
|
|
570
|
+
.replace(/^[-*]\s+(.+)$/gm, (_, text) => {
|
|
571
|
+
return `${chalk.yellow('•')} ${text}`
|
|
572
|
+
})
|
|
573
|
+
// Bold (**text**) - make bold
|
|
574
|
+
.replace(/\*\*(.+?)\*\*/g, (_, text) => {
|
|
575
|
+
return chalk.bold(text)
|
|
576
|
+
})
|
|
577
|
+
// Italic (*text*) - make italic (dim in terminals)
|
|
578
|
+
.replace(/\*(.+?)\*/g, (_, text) => {
|
|
579
|
+
return chalk.italic(text)
|
|
580
|
+
})
|
|
581
|
+
)
|
|
582
|
+
}
|