codeceptjs 3.7.0-beta.4 → 3.7.0-beta.6
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 +9 -10
- package/bin/codecept.js +7 -0
- package/lib/actor.js +47 -92
- package/lib/command/check.js +173 -0
- package/lib/command/definitions.js +2 -0
- package/lib/command/run-workers.js +1 -1
- package/lib/command/workers/runTests.js +112 -109
- package/lib/container.js +9 -0
- package/lib/effects.js +218 -0
- package/lib/heal.js +10 -0
- package/lib/helper/Appium.js +27 -16
- package/lib/helper/Playwright.js +15 -0
- package/lib/helper/Puppeteer.js +5 -0
- package/lib/helper/WebDriver.js +9 -1
- package/lib/listener/emptyRun.js +2 -5
- package/lib/listener/globalTimeout.js +15 -3
- package/lib/listener/steps.js +3 -0
- package/lib/mocha/cli.js +22 -5
- package/lib/mocha/featureConfig.js +13 -0
- package/lib/mocha/scenarioConfig.js +11 -0
- package/lib/mocha/test.js +15 -0
- package/lib/mocha/types.d.ts +6 -0
- package/lib/output.js +74 -73
- package/lib/pause.js +3 -7
- package/lib/plugin/heal.js +30 -0
- package/lib/plugin/retryTo.js +18 -126
- package/lib/plugin/stepTimeout.js +1 -1
- package/lib/plugin/tryTo.js +13 -111
- package/lib/recorder.js +1 -1
- package/lib/step/base.js +180 -0
- package/lib/step/config.js +50 -0
- package/lib/step/helper.js +47 -0
- package/lib/step/meta.js +91 -0
- package/lib/step/record.js +74 -0
- package/lib/step/retry.js +11 -0
- package/lib/step/timeout.js +42 -0
- package/lib/step.js +15 -348
- package/lib/steps.js +23 -0
- package/lib/store.js +2 -0
- package/lib/utils.js +58 -0
- package/lib/within.js +2 -2
- package/lib/workers.js +2 -12
- package/package.json +9 -7
- package/typings/index.d.ts +5 -4
- package/typings/promiseBasedTypes.d.ts +520 -6
- package/typings/types.d.ts +562 -44
- package/lib/step/section.js +0 -25
package/lib/step/base.js
ADDED
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
const color = require('chalk')
|
|
2
|
+
const Secret = require('../secret')
|
|
3
|
+
const { getCurrentTimeout } = require('./timeout')
|
|
4
|
+
const { ucfirst, humanizeString } = require('../utils')
|
|
5
|
+
|
|
6
|
+
const STACK_LINE = 4
|
|
7
|
+
|
|
8
|
+
/**
|
|
9
|
+
* Each command in test executed through `I.` object is wrapped in Step.
|
|
10
|
+
* Step allows logging executed commands and triggers hook before and after step execution.
|
|
11
|
+
* @param {string} name
|
|
12
|
+
*/
|
|
13
|
+
class Step {
|
|
14
|
+
constructor(name) {
|
|
15
|
+
/** @member {string} */
|
|
16
|
+
this.name = name
|
|
17
|
+
/** @member {Map<number, number>} */
|
|
18
|
+
this.timeouts = new Map()
|
|
19
|
+
|
|
20
|
+
/** @member {Array<*>} */
|
|
21
|
+
this.args = []
|
|
22
|
+
|
|
23
|
+
/** @member {Record<string,any>} */
|
|
24
|
+
this.opts = {}
|
|
25
|
+
/** @member {string} */
|
|
26
|
+
this.actor = 'I' // I = actor
|
|
27
|
+
/** @member {string} */
|
|
28
|
+
this.helperMethod = name // helper method
|
|
29
|
+
/** @member {string} */
|
|
30
|
+
this.status = 'pending'
|
|
31
|
+
/** @member {string} */
|
|
32
|
+
this.prefix = this.suffix = ''
|
|
33
|
+
/** @member {string} */
|
|
34
|
+
this.comment = ''
|
|
35
|
+
/** @member {any} */
|
|
36
|
+
this.metaStep = undefined
|
|
37
|
+
/** @member {string} */
|
|
38
|
+
this.stack = ''
|
|
39
|
+
|
|
40
|
+
this.setTrace()
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
setMetaStep(metaStep) {
|
|
44
|
+
this.metaStep = metaStep
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
run() {
|
|
48
|
+
throw new Error('Not implemented')
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
/**
|
|
52
|
+
* @returns {number|undefined}
|
|
53
|
+
*/
|
|
54
|
+
get timeout() {
|
|
55
|
+
return getCurrentTimeout(this.timeouts)
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/**
|
|
59
|
+
* @param {number} timeout - timeout in milliseconds or 0 if no timeout
|
|
60
|
+
* @param {number} order - order defines the priority of timeout, timeouts set with lower order override those set with higher order.
|
|
61
|
+
* When order below 0 value of timeout only override if new value is lower
|
|
62
|
+
*/
|
|
63
|
+
setTimeout(timeout, order) {
|
|
64
|
+
this.timeouts.set(order, timeout)
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** @function */
|
|
68
|
+
setTrace() {
|
|
69
|
+
Error.captureStackTrace(this)
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
/** @param {Array<*>} args */
|
|
73
|
+
setArguments(args) {
|
|
74
|
+
this.args = args
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
setActor(actor) {
|
|
78
|
+
this.actor = actor || ''
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** @param {string} status */
|
|
82
|
+
setStatus(status) {
|
|
83
|
+
this.status = status
|
|
84
|
+
if (this.metaStep) {
|
|
85
|
+
this.metaStep.setStatus(status)
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** @return {string} */
|
|
90
|
+
humanize() {
|
|
91
|
+
return humanizeString(this.name)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/** @return {string} */
|
|
95
|
+
humanizeArgs() {
|
|
96
|
+
return this.args
|
|
97
|
+
.map(arg => {
|
|
98
|
+
if (!arg) {
|
|
99
|
+
return ''
|
|
100
|
+
}
|
|
101
|
+
if (typeof arg === 'string') {
|
|
102
|
+
return `"${arg}"`
|
|
103
|
+
}
|
|
104
|
+
if (Array.isArray(arg)) {
|
|
105
|
+
try {
|
|
106
|
+
const res = JSON.stringify(arg)
|
|
107
|
+
return res
|
|
108
|
+
} catch (err) {
|
|
109
|
+
return `[${arg.toString()}]`
|
|
110
|
+
}
|
|
111
|
+
} else if (typeof arg === 'function') {
|
|
112
|
+
return arg.toString()
|
|
113
|
+
} else if (typeof arg === 'undefined') {
|
|
114
|
+
return `${arg}`
|
|
115
|
+
} else if (arg instanceof Secret) {
|
|
116
|
+
return arg.getMasked()
|
|
117
|
+
} else if (arg.toString && arg.toString() !== '[object Object]') {
|
|
118
|
+
return arg.toString()
|
|
119
|
+
} else if (typeof arg === 'object') {
|
|
120
|
+
const returnedArg = {}
|
|
121
|
+
for (const [key, value] of Object.entries(arg)) {
|
|
122
|
+
returnedArg[key] = value
|
|
123
|
+
if (value instanceof Secret) returnedArg[key] = value.getMasked()
|
|
124
|
+
}
|
|
125
|
+
return JSON.stringify(returnedArg)
|
|
126
|
+
}
|
|
127
|
+
return arg
|
|
128
|
+
})
|
|
129
|
+
.join(', ')
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/** @return {string} */
|
|
133
|
+
line() {
|
|
134
|
+
const lines = this.stack.split('\n')
|
|
135
|
+
if (lines[STACK_LINE]) {
|
|
136
|
+
return lines[STACK_LINE].trim()
|
|
137
|
+
.replace(global.codecept_dir || '', '.')
|
|
138
|
+
.trim()
|
|
139
|
+
}
|
|
140
|
+
return ''
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
/** @return {string} */
|
|
144
|
+
toString() {
|
|
145
|
+
return ucfirst(`${this.prefix}${this.actor} ${this.humanize()} ${this.humanizeArgs()}${this.suffix}`).trim()
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/** @return {string} */
|
|
149
|
+
toCliStyled() {
|
|
150
|
+
return `${this.prefix}${this.actor} ${color.italic(this.humanize())} ${color.yellow(this.humanizeArgs())}${this.suffix}`
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
/** @return {string} */
|
|
154
|
+
toCode() {
|
|
155
|
+
return `${this.prefix}${this.actor}.${this.name}(${this.humanizeArgs()})${this.suffix}`
|
|
156
|
+
}
|
|
157
|
+
|
|
158
|
+
isMetaStep() {
|
|
159
|
+
return this.constructor.name === 'MetaStep'
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
/** @return {boolean} */
|
|
163
|
+
hasBDDAncestor() {
|
|
164
|
+
let hasBDD = false
|
|
165
|
+
let processingStep
|
|
166
|
+
processingStep = this
|
|
167
|
+
|
|
168
|
+
while (processingStep.metaStep) {
|
|
169
|
+
if (processingStep.metaStep.actor.match(/^(Given|When|Then|And)/)) {
|
|
170
|
+
hasBDD = true
|
|
171
|
+
break
|
|
172
|
+
} else {
|
|
173
|
+
processingStep = processingStep.metaStep
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
return hasBDD
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
module.exports = Step
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* StepConfig is a configuration object for a step.
|
|
3
|
+
* It is used to create a new step that is a combination of other steps.
|
|
4
|
+
*/
|
|
5
|
+
class StepConfig {
|
|
6
|
+
constructor(opts = {}) {
|
|
7
|
+
/** @member {{ opts: Record<string, any>, timeout: number|undefined, retry: number|undefined }} */
|
|
8
|
+
this.config = {
|
|
9
|
+
opts,
|
|
10
|
+
timeout: undefined,
|
|
11
|
+
retry: undefined,
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* Set the options for the step.
|
|
17
|
+
* @param {object} opts - The options for the step.
|
|
18
|
+
* @returns {StepConfig} - The step configuration object.
|
|
19
|
+
*/
|
|
20
|
+
opts(opts) {
|
|
21
|
+
this.config.opts = opts
|
|
22
|
+
return this
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
/**
|
|
26
|
+
* Set the timeout for the step.
|
|
27
|
+
* @param {number} timeout - The timeout for the step.
|
|
28
|
+
* @returns {StepConfig} - The step configuration object.
|
|
29
|
+
*/
|
|
30
|
+
timeout(timeout) {
|
|
31
|
+
this.config.timeout = timeout
|
|
32
|
+
return this
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
/**
|
|
36
|
+
* Set the retry for the step.
|
|
37
|
+
* @param {number} retry - The retry for the step.
|
|
38
|
+
* @returns {StepConfig} - The step configuration object.
|
|
39
|
+
*/
|
|
40
|
+
retry(retry) {
|
|
41
|
+
this.config.retry = retry
|
|
42
|
+
return this
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
getConfig() {
|
|
46
|
+
return this.config
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
module.exports = StepConfig
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
const Step = require('./base')
|
|
2
|
+
const store = require('../store')
|
|
3
|
+
|
|
4
|
+
class HelperStep extends Step {
|
|
5
|
+
constructor(helper, name) {
|
|
6
|
+
super(name)
|
|
7
|
+
/** @member {CodeceptJS.Helper} helper corresponding helper */
|
|
8
|
+
this.helper = helper
|
|
9
|
+
/** @member {string} helperMethod name of method to be executed */
|
|
10
|
+
this.helperMethod = name
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* @param {...any} args
|
|
15
|
+
* @return {*}
|
|
16
|
+
*/
|
|
17
|
+
run() {
|
|
18
|
+
this.args = Array.prototype.slice.call(arguments)
|
|
19
|
+
|
|
20
|
+
if (store.dryRun) {
|
|
21
|
+
this.setStatus('success')
|
|
22
|
+
return Promise.resolve(new Proxy({}, dryRunResolver()))
|
|
23
|
+
}
|
|
24
|
+
let result
|
|
25
|
+
try {
|
|
26
|
+
if (this.helperMethod !== 'say') {
|
|
27
|
+
result = this.helper[this.helperMethod].apply(this.helper, this.args)
|
|
28
|
+
}
|
|
29
|
+
this.setStatus('success')
|
|
30
|
+
} catch (err) {
|
|
31
|
+
this.setStatus('failed')
|
|
32
|
+
throw err
|
|
33
|
+
}
|
|
34
|
+
return result
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
module.exports = HelperStep
|
|
39
|
+
|
|
40
|
+
function dryRunResolver() {
|
|
41
|
+
return {
|
|
42
|
+
get(target, prop) {
|
|
43
|
+
if (prop === 'toString') return () => '<VALUE>'
|
|
44
|
+
return new Proxy({}, dryRunResolver())
|
|
45
|
+
},
|
|
46
|
+
}
|
|
47
|
+
}
|
package/lib/step/meta.js
ADDED
|
@@ -0,0 +1,91 @@
|
|
|
1
|
+
const Step = require('./base')
|
|
2
|
+
const event = require('../event')
|
|
3
|
+
const { humanizeString } = require('../utils')
|
|
4
|
+
|
|
5
|
+
class MetaStep extends Step {
|
|
6
|
+
constructor(actor, method) {
|
|
7
|
+
if (!method) method = ''
|
|
8
|
+
super(method)
|
|
9
|
+
this.actor = actor
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/** @return {boolean} */
|
|
13
|
+
isBDD() {
|
|
14
|
+
if (this.actor && this.actor.match && this.actor.match(/^(Given|When|Then|And)/)) {
|
|
15
|
+
return true
|
|
16
|
+
}
|
|
17
|
+
return false
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
toCliStyled() {
|
|
21
|
+
return this.toString()
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
toString() {
|
|
25
|
+
const actorText = this.actor
|
|
26
|
+
|
|
27
|
+
if (this.isBDD()) {
|
|
28
|
+
return `${this.prefix}${actorText} ${this.name} "${this.humanizeArgs()}${this.suffix}"`
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
if (actorText === 'I') {
|
|
32
|
+
return `${this.prefix}${actorText} ${this.humanize()} ${this.humanizeArgs()}${this.suffix}`
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
return `On ${this.prefix}${actorText}: ${this.humanize()} ${this.humanizeArgs()}${this.suffix}`
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
humanize() {
|
|
39
|
+
return humanizeString(this.name)
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
setTrace() {}
|
|
43
|
+
|
|
44
|
+
setContext(context) {
|
|
45
|
+
this.context = context
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
/** @return {*} */
|
|
49
|
+
run(fn) {
|
|
50
|
+
this.status = 'queued'
|
|
51
|
+
this.setArguments(Array.from(arguments).slice(1))
|
|
52
|
+
let result
|
|
53
|
+
|
|
54
|
+
const registerStep = step => {
|
|
55
|
+
this.setMetaStep(null)
|
|
56
|
+
step.setMetaStep(this)
|
|
57
|
+
}
|
|
58
|
+
event.dispatcher.prependListener(event.step.before, registerStep)
|
|
59
|
+
// Handle async and sync methods.
|
|
60
|
+
if (fn.constructor.name === 'AsyncFunction') {
|
|
61
|
+
result = fn
|
|
62
|
+
.apply(this.context, this.args)
|
|
63
|
+
.then(result => {
|
|
64
|
+
return result
|
|
65
|
+
})
|
|
66
|
+
.catch(error => {
|
|
67
|
+
this.setStatus('failed')
|
|
68
|
+
throw error
|
|
69
|
+
})
|
|
70
|
+
.finally(() => {
|
|
71
|
+
this.endTime = Date.now()
|
|
72
|
+
event.dispatcher.removeListener(event.step.before, registerStep)
|
|
73
|
+
})
|
|
74
|
+
} else {
|
|
75
|
+
try {
|
|
76
|
+
this.startTime = Date.now()
|
|
77
|
+
result = fn.apply(this.context, this.args)
|
|
78
|
+
} catch (error) {
|
|
79
|
+
this.setStatus('failed')
|
|
80
|
+
throw error
|
|
81
|
+
} finally {
|
|
82
|
+
this.endTime = Date.now()
|
|
83
|
+
event.dispatcher.removeListener(event.step.before, registerStep)
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
return result
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
module.exports = MetaStep
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
const event = require('../event')
|
|
2
|
+
const recorder = require('../recorder')
|
|
3
|
+
const StepConfig = require('./config')
|
|
4
|
+
const { debug } = require('../output')
|
|
5
|
+
const store = require('../store')
|
|
6
|
+
const { TIMEOUT_ORDER } = require('./timeout')
|
|
7
|
+
const retryStep = require('./retry')
|
|
8
|
+
function recordStep(step, args) {
|
|
9
|
+
step.status = 'queued'
|
|
10
|
+
|
|
11
|
+
// apply step configuration
|
|
12
|
+
const lastArg = args[args.length - 1]
|
|
13
|
+
if (lastArg instanceof StepConfig) {
|
|
14
|
+
const stepConfig = args.pop()
|
|
15
|
+
const { opts, timeout, retry } = stepConfig.getConfig()
|
|
16
|
+
|
|
17
|
+
if (opts) {
|
|
18
|
+
debug(`Step ${step.name}: options applied ${JSON.stringify(opts)}`)
|
|
19
|
+
store.stepOptions = opts
|
|
20
|
+
step.opts = opts
|
|
21
|
+
}
|
|
22
|
+
if (timeout) {
|
|
23
|
+
debug(`Step ${step.name} timeout ${timeout}s`)
|
|
24
|
+
step.setTimeout(timeout * 1000, TIMEOUT_ORDER.codeLimitTime)
|
|
25
|
+
}
|
|
26
|
+
if (retry) retryStep(retry)
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
step.setArguments(args)
|
|
30
|
+
// run async before step hooks
|
|
31
|
+
event.emit(event.step.before, step)
|
|
32
|
+
|
|
33
|
+
const task = `${step.name}: ${step.humanizeArgs()}`
|
|
34
|
+
let val
|
|
35
|
+
|
|
36
|
+
// run step inside promise
|
|
37
|
+
recorder.add(
|
|
38
|
+
task,
|
|
39
|
+
() => {
|
|
40
|
+
if (!step.startTime) {
|
|
41
|
+
// step can be retries
|
|
42
|
+
event.emit(event.step.started, step)
|
|
43
|
+
step.startTime = Date.now()
|
|
44
|
+
}
|
|
45
|
+
return (val = step.run(...args))
|
|
46
|
+
},
|
|
47
|
+
false,
|
|
48
|
+
undefined,
|
|
49
|
+
step.timeout,
|
|
50
|
+
)
|
|
51
|
+
|
|
52
|
+
event.emit(event.step.after, step)
|
|
53
|
+
|
|
54
|
+
recorder.add('step passed', () => {
|
|
55
|
+
step.endTime = Date.now()
|
|
56
|
+
event.emit(event.step.passed, step, val)
|
|
57
|
+
event.emit(event.step.finished, step)
|
|
58
|
+
})
|
|
59
|
+
|
|
60
|
+
recorder.catchWithoutStop(err => {
|
|
61
|
+
step.status = 'failed'
|
|
62
|
+
step.endTime = Date.now()
|
|
63
|
+
event.emit(event.step.failed, step)
|
|
64
|
+
event.emit(event.step.finished, step)
|
|
65
|
+
throw err
|
|
66
|
+
})
|
|
67
|
+
|
|
68
|
+
recorder.add('return result', () => val)
|
|
69
|
+
// run async after step hooks
|
|
70
|
+
|
|
71
|
+
return recorder.promise()
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
module.exports = recordStep
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
const recorder = require('../recorder')
|
|
2
|
+
const event = require('../event')
|
|
3
|
+
|
|
4
|
+
function retryStep(opts) {
|
|
5
|
+
if (opts === undefined) opts = 1
|
|
6
|
+
recorder.retry(opts)
|
|
7
|
+
// remove retry once the step passed
|
|
8
|
+
recorder.add(() => event.dispatcher.once(event.step.finished, () => recorder.retries.pop()))
|
|
9
|
+
}
|
|
10
|
+
|
|
11
|
+
module.exports = retryStep
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
const TIMEOUT_ORDER = {
|
|
2
|
+
/**
|
|
3
|
+
* timeouts set with order below zero only override timeouts of higher order if their value is smaller
|
|
4
|
+
*/
|
|
5
|
+
testOrSuite: -5,
|
|
6
|
+
/**
|
|
7
|
+
* 0-9 - designated for override of timeouts set from code, 5 is used by stepTimeout plugin when stepTimeout.config.overrideStepLimits=true
|
|
8
|
+
*/
|
|
9
|
+
stepTimeoutHard: 5,
|
|
10
|
+
/**
|
|
11
|
+
* 10-19 - designated for timeouts set from code, 15 is order of I.setTimeout(t) operation
|
|
12
|
+
*/
|
|
13
|
+
codeLimitTime: 15,
|
|
14
|
+
/**
|
|
15
|
+
* 20-29 - designated for timeout settings which could be overriden in tests code, 25 is used by stepTimeout plugin when stepTimeout.config.overrideStepLimits=false
|
|
16
|
+
*/
|
|
17
|
+
stepTimeoutSoft: 25,
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
function getCurrentTimeout(timeouts) {
|
|
21
|
+
let totalTimeout
|
|
22
|
+
// iterate over all timeouts starting from highest values of order
|
|
23
|
+
new Map([...timeouts.entries()].sort().reverse()).forEach((timeout, order) => {
|
|
24
|
+
if (
|
|
25
|
+
timeout !== undefined &&
|
|
26
|
+
// when orders >= 0 - timeout value overrides those set with higher order elements
|
|
27
|
+
(order >= 0 ||
|
|
28
|
+
// when `order < 0 && totalTimeout === undefined` - timeout is used when nothing is set by elements with higher order
|
|
29
|
+
totalTimeout === undefined ||
|
|
30
|
+
// when `order < 0` - timeout overrides higher values of timeout or 'no timeout' (totalTimeout === 0) set by elements with higher order
|
|
31
|
+
(timeout > 0 && (timeout < totalTimeout || totalTimeout === 0)))
|
|
32
|
+
) {
|
|
33
|
+
totalTimeout = timeout
|
|
34
|
+
}
|
|
35
|
+
})
|
|
36
|
+
return totalTimeout
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
module.exports = {
|
|
40
|
+
TIMEOUT_ORDER,
|
|
41
|
+
getCurrentTimeout,
|
|
42
|
+
}
|