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.
Files changed (47) hide show
  1. package/README.md +9 -10
  2. package/bin/codecept.js +7 -0
  3. package/lib/actor.js +47 -92
  4. package/lib/command/check.js +173 -0
  5. package/lib/command/definitions.js +2 -0
  6. package/lib/command/run-workers.js +1 -1
  7. package/lib/command/workers/runTests.js +112 -109
  8. package/lib/container.js +9 -0
  9. package/lib/effects.js +218 -0
  10. package/lib/heal.js +10 -0
  11. package/lib/helper/Appium.js +27 -16
  12. package/lib/helper/Playwright.js +15 -0
  13. package/lib/helper/Puppeteer.js +5 -0
  14. package/lib/helper/WebDriver.js +9 -1
  15. package/lib/listener/emptyRun.js +2 -5
  16. package/lib/listener/globalTimeout.js +15 -3
  17. package/lib/listener/steps.js +3 -0
  18. package/lib/mocha/cli.js +22 -5
  19. package/lib/mocha/featureConfig.js +13 -0
  20. package/lib/mocha/scenarioConfig.js +11 -0
  21. package/lib/mocha/test.js +15 -0
  22. package/lib/mocha/types.d.ts +6 -0
  23. package/lib/output.js +74 -73
  24. package/lib/pause.js +3 -7
  25. package/lib/plugin/heal.js +30 -0
  26. package/lib/plugin/retryTo.js +18 -126
  27. package/lib/plugin/stepTimeout.js +1 -1
  28. package/lib/plugin/tryTo.js +13 -111
  29. package/lib/recorder.js +1 -1
  30. package/lib/step/base.js +180 -0
  31. package/lib/step/config.js +50 -0
  32. package/lib/step/helper.js +47 -0
  33. package/lib/step/meta.js +91 -0
  34. package/lib/step/record.js +74 -0
  35. package/lib/step/retry.js +11 -0
  36. package/lib/step/timeout.js +42 -0
  37. package/lib/step.js +15 -348
  38. package/lib/steps.js +23 -0
  39. package/lib/store.js +2 -0
  40. package/lib/utils.js +58 -0
  41. package/lib/within.js +2 -2
  42. package/lib/workers.js +2 -12
  43. package/package.json +9 -7
  44. package/typings/index.d.ts +5 -4
  45. package/typings/promiseBasedTypes.d.ts +520 -6
  46. package/typings/types.d.ts +562 -44
  47. package/lib/step/section.js +0 -25
package/lib/step.js CHANGED
@@ -1,353 +1,20 @@
1
- // TODO: place MetaStep in other file, disable rule
2
-
3
- const color = require('chalk')
4
- const store = require('./store')
5
- const Secret = require('./secret')
6
- const event = require('./event')
7
- const { ucfirst } = require('./utils')
8
-
9
- const STACK_LINE = 4
10
-
1
+ // refactored step class, moved to helper
11
2
  /**
12
- * Each command in test executed through `I.` object is wrapped in Step.
13
- * Step allows logging executed commands and triggers hook before and after step execution.
14
- * @param {CodeceptJS.Helper} helper
15
- * @param {string} name
3
+ * Step is wrapper around a helper method.
4
+ * It is used to create a new step that is a combination of other steps.
16
5
  */
17
- class Step {
18
- static get TIMEOUT_ORDER() {
19
- return {
20
- /**
21
- * timeouts set with order below zero only override timeouts of higher order if their value is smaller
22
- */
23
- testOrSuite: -5,
24
- /**
25
- * 0-9 - designated for override of timeouts set from code, 5 is used by stepTimeout plugin when stepTimeout.config.overrideStepLimits=true
26
- */
27
- stepTimeoutHard: 5,
28
- /**
29
- * 10-19 - designated for timeouts set from code, 15 is order of I.setTimeout(t) operation
30
- */
31
- codeLimitTime: 15,
32
- /**
33
- * 20-29 - designated for timeout settings which could be overriden in tests code, 25 is used by stepTimeout plugin when stepTimeout.config.overrideStepLimits=false
34
- */
35
- stepTimeoutSoft: 25,
36
- }
37
- }
38
-
39
- constructor(helper, name) {
40
- /** @member {string} */
41
- this.actor = 'I' // I = actor
42
- /** @member {CodeceptJS.Helper} */
43
- this.helper = helper // corresponding helper
44
- /** @member {string} */
45
- this.name = name // name of a step console
46
- /** @member {string} */
47
- this.helperMethod = name // helper method
48
- /** @member {string} */
49
- this.status = 'pending'
50
- /**
51
- * @member {string} suffix
52
- * @memberof CodeceptJS.Step#
53
- */
54
- /** @member {string} */
55
- this.prefix = this.suffix = ''
56
- /** @member {string} */
57
- this.comment = ''
58
- /** @member {Array<*>} */
59
- this.args = []
60
- /** @member {MetaStep} */
61
- this.metaStep = undefined
62
- /** @member {string} */
63
- this.stack = ''
64
-
65
- const timeouts = new Map()
66
- /**
67
- * @method
68
- * @returns {number|undefined}
69
- */
70
- this.getTimeout = function () {
71
- let totalTimeout
72
- // iterate over all timeouts starting from highest values of order
73
- new Map([...timeouts.entries()].sort().reverse()).forEach((timeout, order) => {
74
- if (
75
- timeout !== undefined &&
76
- // when orders >= 0 - timeout value overrides those set with higher order elements
77
- (order >= 0 ||
78
- // when `order < 0 && totalTimeout === undefined` - timeout is used when nothing is set by elements with higher order
79
- totalTimeout === undefined ||
80
- // when `order < 0` - timeout overrides higher values of timeout or 'no timeout' (totalTimeout === 0) set by elements with higher order
81
- (timeout > 0 && (timeout < totalTimeout || totalTimeout === 0)))
82
- ) {
83
- totalTimeout = timeout
84
- }
85
- })
86
- return totalTimeout
87
- }
88
- /**
89
- * @method
90
- * @param {number} timeout - timeout in milliseconds or 0 if no timeout
91
- * @param {number} order - order defines the priority of timeout, timeouts set with lower order override those set with higher order.
92
- * When order below 0 value of timeout only override if new value is lower
93
- */
94
- this.setTimeout = function (timeout, order) {
95
- timeouts.set(order, timeout)
96
- }
97
-
98
- this.setTrace()
99
- }
100
-
101
- /** @function */
102
- setTrace() {
103
- Error.captureStackTrace(this)
104
- }
105
-
106
- /** @param {Array<*>} args */
107
- setArguments(args) {
108
- this.args = args
109
- }
110
-
111
- /**
112
- * @param {...any} args
113
- * @return {*}
114
- */
115
- run() {
116
- this.args = Array.prototype.slice.call(arguments)
117
- if (store.dryRun) {
118
- this.setStatus('success')
119
- return Promise.resolve(new Proxy({}, dryRunResolver()))
120
- }
121
- let result
122
- try {
123
- if (this.helperMethod !== 'say') {
124
- result = this.helper[this.helperMethod].apply(this.helper, this.args)
125
- }
126
- this.setStatus('success')
127
- } catch (err) {
128
- this.setStatus('failed')
129
- throw err
130
- }
131
- return result
132
- }
133
-
134
- setActor(actor) {
135
- this.actor = actor || ''
136
- }
137
-
138
- /** @param {string} status */
139
- setStatus(status) {
140
- this.status = status
141
- if (this.metaStep) {
142
- this.metaStep.setStatus(status)
143
- }
144
- }
145
-
146
- /** @return {string} */
147
- humanize() {
148
- return humanizeString(this.name)
149
- }
150
-
151
- /** @return {string} */
152
- humanizeArgs() {
153
- return this.args
154
- .map(arg => {
155
- if (!arg) {
156
- return ''
157
- }
158
- if (typeof arg === 'string') {
159
- return `"${arg}"`
160
- }
161
- if (Array.isArray(arg)) {
162
- try {
163
- const res = JSON.stringify(arg)
164
- return res
165
- } catch (err) {
166
- return `[${arg.toString()}]`
167
- }
168
- } else if (typeof arg === 'function') {
169
- return arg.toString()
170
- } else if (typeof arg === 'undefined') {
171
- return `${arg}`
172
- } else if (arg instanceof Secret) {
173
- return arg.getMasked()
174
- } else if (arg.toString && arg.toString() !== '[object Object]') {
175
- return arg.toString()
176
- } else if (typeof arg === 'object') {
177
- const returnedArg = {}
178
- for (const [key, value] of Object.entries(arg)) {
179
- returnedArg[key] = value
180
- if (value instanceof Secret) returnedArg[key] = value.getMasked()
181
- }
182
- return JSON.stringify(returnedArg)
183
- }
184
- return arg
185
- })
186
- .join(', ')
187
- }
188
-
189
- /** @return {string} */
190
- line() {
191
- const lines = this.stack.split('\n')
192
- if (lines[STACK_LINE]) {
193
- return lines[STACK_LINE].trim()
194
- .replace(global.codecept_dir || '', '.')
195
- .trim()
196
- }
197
- return ''
198
- }
199
-
200
- /** @return {string} */
201
- toString() {
202
- return ucfirst(`${this.prefix}${this.actor} ${this.humanize()} ${this.humanizeArgs()}${this.suffix}`).trim()
203
- }
204
-
205
- /** @return {string} */
206
- toCliStyled() {
207
- return `${this.prefix}${this.actor} ${color.italic(this.humanize())} ${color.yellow(this.humanizeArgs())}${this.suffix}`
208
- }
209
-
210
- /** @return {string} */
211
- toCode() {
212
- return `${this.prefix}${this.actor}.${this.name}(${this.humanizeArgs()})${this.suffix}`
213
- }
214
-
215
- isMetaStep() {
216
- return this.constructor.name === 'MetaStep'
217
- }
218
-
219
- /** @return {boolean} */
220
- hasBDDAncestor() {
221
- let hasBDD = false
222
- let processingStep
223
- processingStep = this
224
-
225
- while (processingStep.metaStep) {
226
- if (processingStep.metaStep.actor.match(/^(Given|When|Then|And)/)) {
227
- hasBDD = true
228
- break
229
- } else {
230
- processingStep = processingStep.metaStep
231
- }
232
- }
233
- return hasBDD
234
- }
235
- }
6
+ const BaseStep = require('./step/base')
7
+ const StepConfig = require('./step/config')
8
+ const Step = require('./step/helper')
236
9
 
237
- /** @extends Step */
238
- class MetaStep extends Step {
239
- constructor(obj, method) {
240
- if (!method) method = ''
241
- super(null, method)
242
- this.actor = obj
243
- }
244
-
245
- /** @return {boolean} */
246
- isBDD() {
247
- if (this.actor && this.actor.match && this.actor.match(/^(Given|When|Then|And)/)) {
248
- return true
249
- }
250
- return false
251
- }
252
-
253
- toCliStyled() {
254
- return this.toString()
255
- }
256
-
257
- toString() {
258
- const actorText = this.actor
259
-
260
- if (this.isBDD()) {
261
- return `${this.prefix}${actorText} ${this.name} "${this.humanizeArgs()}${this.suffix}"`
262
- }
263
-
264
- if (actorText === 'I') {
265
- return `${this.prefix}${actorText} ${this.humanize()} ${this.humanizeArgs()}${this.suffix}`
266
- }
267
-
268
- return `On ${this.prefix}${actorText}: ${this.humanize()} ${this.humanizeArgs()}${this.suffix}`
269
- }
270
-
271
- humanize() {
272
- return humanizeString(this.name)
273
- }
274
-
275
- setTrace() {}
276
-
277
- setContext(context) {
278
- this.context = context
279
- }
280
-
281
- /** @return {*} */
282
- run(fn) {
283
- this.status = 'queued'
284
- this.setArguments(Array.from(arguments).slice(1))
285
- let result
286
-
287
- const registerStep = step => {
288
- this.metaStep = null
289
- step.metaStep = this
290
- }
291
- event.dispatcher.prependListener(event.step.before, registerStep)
292
- // Handle async and sync methods.
293
- if (fn.constructor.name === 'AsyncFunction') {
294
- result = fn
295
- .apply(this.context, this.args)
296
- .then(result => {
297
- return result
298
- })
299
- .catch(error => {
300
- this.setStatus('failed')
301
- throw error
302
- })
303
- .finally(() => {
304
- this.endTime = Date.now()
305
- event.dispatcher.removeListener(event.step.before, registerStep)
306
- })
307
- } else {
308
- try {
309
- this.startTime = Date.now()
310
- result = fn.apply(this.context, this.args)
311
- } catch (error) {
312
- this.setStatus('failed')
313
- throw error
314
- } finally {
315
- this.endTime = Date.now()
316
- event.dispatcher.removeListener(event.step.before, registerStep)
317
- }
318
- }
319
-
320
- return result
321
- }
322
- }
323
-
324
- Step.TIMEOUTS = {}
325
-
326
- /** @type {Class<MetaStep>} */
327
- Step.MetaStep = MetaStep
10
+ /**
11
+ * MetaStep is a step that is used to wrap other steps.
12
+ * It is used to create a new step that is a combination of other steps.
13
+ * It is used to create a new step that is a combination of other steps.
14
+ */
15
+ const MetaStep = require('./step/meta')
328
16
 
329
17
  module.exports = Step
330
-
331
- function dryRunResolver() {
332
- return {
333
- get(target, prop) {
334
- if (prop === 'toString') return () => '<VALUE>'
335
- return new Proxy({}, dryRunResolver())
336
- },
337
- }
338
- }
339
-
340
- function humanizeString(string) {
341
- // split strings by words, then make them all lowercase
342
- const _result = string
343
- .replace(/([a-z](?=[A-Z]))/g, '$1 ')
344
- .split(' ')
345
- .map(word => word.toLowerCase())
346
-
347
- _result[0] = _result[0] === 'i' ? capitalizeFLetter(_result[0]) : _result[0]
348
- return _result.join(' ').trim()
349
- }
350
-
351
- function capitalizeFLetter(string) {
352
- return string[0].toUpperCase() + string.slice(1)
353
- }
18
+ module.exports.MetaStep = MetaStep
19
+ module.exports.BaseStep = BaseStep
20
+ module.exports.StepConfig = StepConfig
package/lib/steps.js ADDED
@@ -0,0 +1,23 @@
1
+ const StepConfig = require('./step/config')
2
+
3
+ function stepOpts(opts = {}) {
4
+ return new StepConfig(opts)
5
+ }
6
+
7
+ function stepTimeout(timeout) {
8
+ return new StepConfig().timeout(timeout)
9
+ }
10
+
11
+ function stepRetry(retry) {
12
+ return new StepConfig().retry(retry)
13
+ }
14
+
15
+ // Section function to be added here
16
+
17
+ const step = {
18
+ opts: stepOpts,
19
+ timeout: stepTimeout,
20
+ retry: stepRetry,
21
+ }
22
+
23
+ module.exports = step
package/lib/store.js CHANGED
@@ -13,6 +13,8 @@ const store = {
13
13
  onPause: false,
14
14
  /** @type {CodeceptJS.Test | null} */
15
15
  currentTest: null,
16
+ /** @type {any} */
17
+ currentStep: null,
16
18
  }
17
19
 
18
20
  module.exports = store
package/lib/utils.js CHANGED
@@ -4,6 +4,7 @@ const path = require('path')
4
4
  const getFunctionArguments = require('fn-args')
5
5
  const deepClone = require('lodash.clonedeep')
6
6
  const { convertColorToRGBA, isColorProperty } = require('./colorUtils')
7
+ const Fuse = require('fuse.js')
7
8
 
8
9
  function deepMerge(target, source) {
9
10
  const merge = require('lodash.merge')
@@ -484,3 +485,60 @@ module.exports.humanizeFunction = function (fn) {
484
485
 
485
486
  return simplified
486
487
  }
488
+
489
+ /**
490
+ * Searches through a given data source using the Fuse.js library for fuzzy searching.
491
+ *
492
+ * @function searchWithFusejs
493
+ * @param {Array|Object} source - The data source to search through. This can be an array of objects or strings.
494
+ * @param {string} searchString - The search query string to match against the source.
495
+ * @param {Object} [opts] - Optional configuration object for Fuse.js.
496
+ * @param {boolean} [opts.includeScore=true] - Whether to include the score of the match in the results.
497
+ * @param {number} [opts.threshold=0.6] - Determines the match threshold; lower values mean stricter matching.
498
+ * @param {boolean} [opts.caseSensitive=false] - Whether the search should be case-sensitive.
499
+ * @param {number} [opts.distance=100] - Determines how far apart the search term is allowed to be from the target.
500
+ * @param {number} [opts.maxPatternLength=32] - The maximum length of the search pattern. Patterns longer than this are ignored.
501
+ * @param {boolean} [opts.ignoreLocation=false] - Whether the location of the match is ignored when scoring.
502
+ * @param {boolean} [opts.ignoreFieldNorm=false] - When true, the field's length is not considered when scoring.
503
+ * @param {Array<string>} [opts.keys=[]] - List of keys to search in the objects of the source array.
504
+ * @param {boolean} [opts.shouldSort=true] - Whether the results should be sorted by score.
505
+ * @param {string} [opts.sortFn] - A custom sorting function for sorting results.
506
+ * @param {number} [opts.minMatchCharLength=1] - The minimum number of characters that must match.
507
+ * @param {boolean} [opts.useExtendedSearch=false] - Enables extended search capabilities.
508
+ *
509
+ * @returns {Array<Object>} - An array of search results. Each result contains an item and, if `includeScore` is true, a score.
510
+ *
511
+ * @example
512
+ * const data = [
513
+ * { title: "Old Man's War", author: "John Scalzi" },
514
+ * { title: "The Lock Artist", author: "Steve Hamilton" },
515
+ * ];
516
+ *
517
+ * const options = {
518
+ * keys: ['title', 'author'],
519
+ * includeScore: true,
520
+ * threshold: 0.4,
521
+ * caseSensitive: false,
522
+ * distance: 50,
523
+ * ignoreLocation: true,
524
+ * };
525
+ *
526
+ * const results = searchWithFusejs(data, 'lock', options);
527
+ * console.log(results);
528
+ */
529
+ module.exports.searchWithFusejs = function (source, searchString, opts) {
530
+ const fuse = new Fuse(source, opts)
531
+
532
+ return fuse.search(searchString)
533
+ }
534
+
535
+ module.exports.humanizeString = function (string) {
536
+ // split strings by words, then make them all lowercase
537
+ const _result = string
538
+ .replace(/([a-z](?=[A-Z]))/g, '$1 ')
539
+ .split(' ')
540
+ .map(word => word.toLowerCase())
541
+
542
+ _result[0] = _result[0] === 'i' ? this.ucfirst(_result[0]) : _result[0]
543
+ return _result.join(' ').trim()
544
+ }
package/lib/within.js CHANGED
@@ -3,7 +3,7 @@ const store = require('./store')
3
3
  const recorder = require('./recorder')
4
4
  const container = require('./container')
5
5
  const event = require('./event')
6
- const Step = require('./step')
6
+ const MetaStep = require('./step/meta')
7
7
  const { isAsyncFunction } = require('./utils')
8
8
 
9
9
  /**
@@ -76,7 +76,7 @@ function within(context, fn) {
76
76
 
77
77
  module.exports = within
78
78
 
79
- class WithinStep extends Step.MetaStep {
79
+ class WithinStep extends MetaStep {
80
80
  constructor(locator, fn) {
81
81
  super('Within')
82
82
  this.args = [locator]
package/lib/workers.js CHANGED
@@ -1,11 +1,6 @@
1
1
  const path = require('path')
2
2
  const mkdirp = require('mkdirp')
3
3
  const { Worker } = require('worker_threads')
4
- const {
5
- Suite,
6
- Test,
7
- reporters: { Base },
8
- } = require('mocha')
9
4
  const { EventEmitter } = require('events')
10
5
  const ms = require('ms')
11
6
  const Codecept = require('./codecept')
@@ -17,6 +12,7 @@ const { replaceValueDeep, deepClone } = require('./utils')
17
12
  const mainConfig = require('./config')
18
13
  const output = require('./output')
19
14
  const event = require('./event')
15
+ const { repackTestForWorkersTransport: repackTest } = require('./mocha/test')
20
16
  const recorder = require('./recorder')
21
17
  const runHook = require('./hooks')
22
18
  const WorkerStorage = require('./workerStorage')
@@ -78,12 +74,6 @@ const simplifyObject = object => {
78
74
  }, {})
79
75
  }
80
76
 
81
- const repackTest = test => {
82
- test = Object.assign(new Test(test.title || '', () => {}), test)
83
- test.parent = Object.assign(new Suite(test.parent.title), test.parent)
84
- return test
85
- }
86
-
87
77
  const createWorkerObjects = (testGroups, config, testRoot, options, selectedRuns) => {
88
78
  selectedRuns = options && options.all && config.multiple ? Object.keys(config.multiple) : selectedRuns
89
79
  if (selectedRuns === undefined || !selectedRuns.length || config.multiple === undefined) {
@@ -459,7 +449,7 @@ class Workers extends EventEmitter {
459
449
  }
460
450
 
461
451
  _finishRun() {
462
- event.dispatcher.emit(event.workers.after)
452
+ event.dispatcher.emit(event.workers.after, { tests: this.workers.map(worker => worker.tests) })
463
453
  if (this.isFailed()) {
464
454
  process.exitCode = 1
465
455
  } else {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeceptjs",
3
- "version": "3.7.0-beta.4",
3
+ "version": "3.7.0-beta.6",
4
4
  "description": "Supercharged End 2 End Testing Framework for NodeJS",
5
5
  "keywords": [
6
6
  "acceptance",
@@ -31,7 +31,9 @@
31
31
  "main": "lib/index.js",
32
32
  "exports": {
33
33
  ".": "./lib/index.js",
34
- "./els": "./lib/els.js"
34
+ "./els": "./lib/els.js",
35
+ "./effects": "./lib/effects.js",
36
+ "./steps": "./lib/steps.js"
35
37
  },
36
38
  "types": "typings/index.d.ts",
37
39
  "bin": {
@@ -114,14 +116,14 @@
114
116
  "uuid": "11.0.4"
115
117
  },
116
118
  "optionalDependencies": {
117
- "@codeceptjs/detox-helper": "1.1.4"
119
+ "@codeceptjs/detox-helper": "1.1.5"
118
120
  },
119
121
  "devDependencies": {
120
122
  "@apollo/server": "^4",
121
123
  "@codeceptjs/expect-helper": "^0.2.2",
122
124
  "@codeceptjs/mock-request": "0.3.1",
123
125
  "@eslint/eslintrc": "3.2.0",
124
- "@eslint/js": "9.17.0",
126
+ "@eslint/js": "9.18.0",
125
127
  "@faker-js/faker": "9.3.0",
126
128
  "@pollyjs/adapter-puppeteer": "6.0.6",
127
129
  "@pollyjs/core": "5.1.0",
@@ -136,7 +138,7 @@
136
138
  "chai-as-promised": "7.1.2",
137
139
  "chai-subset": "1.6.0",
138
140
  "documentation": "14.0.3",
139
- "electron": "33.2.1",
141
+ "electron": "33.3.1",
140
142
  "eslint": "^9.17.0",
141
143
  "eslint-plugin-import": "2.31.0",
142
144
  "eslint-plugin-mocha": "10.5.0",
@@ -152,7 +154,7 @@
152
154
  "json-server": "0.17.4",
153
155
  "playwright": "1.49.1",
154
156
  "prettier": "^3.3.2",
155
- "puppeteer": "23.11.1",
157
+ "puppeteer": "24.0.0",
156
158
  "qrcode-terminal": "0.12.0",
157
159
  "rosie": "2.1.1",
158
160
  "runok": "0.9.3",
@@ -166,7 +168,7 @@
166
168
  "tsd-jsdoc": "2.5.0",
167
169
  "typedoc": "0.27.6",
168
170
  "typedoc-plugin-markdown": "4.4.1",
169
- "typescript": "5.7.2",
171
+ "typescript": "5.7.3",
170
172
  "wdio-docker-service": "1.5.0",
171
173
  "webdriverio": "^9.5.1",
172
174
  "xml2js": "0.6.2",
@@ -451,9 +451,6 @@ declare namespace CodeceptJS {
451
451
  }
452
452
 
453
453
  // Extending JSDoc generated typings
454
- interface Step {
455
- isMetaStep(): this is MetaStep
456
- }
457
454
 
458
455
  // Types who are not be defined by JSDoc
459
456
  type actor = <T extends { [action: string]: (...args: any[]) => void }>(customSteps?: T & ThisType<WithTranslation<Methods & T>>) => WithTranslation<Methods & T>
@@ -502,7 +499,7 @@ declare namespace CodeceptJS {
502
499
  (title: string, opts: { [key: string]: any }, callback: HookCallback): ScenarioConfig
503
500
  }
504
501
  interface IHook {
505
- (callback: HookCallback): void
502
+ (callback: HookCallback): HookConfig
506
503
  }
507
504
 
508
505
  interface Globals {
@@ -516,6 +513,10 @@ declare namespace CodeceptJS {
516
513
  useForSnippets?: boolean
517
514
  preferForRegexpMatch?: boolean
518
515
  }
516
+
517
+ interface HookConfig {
518
+ retry(retries?: number): HookConfig
519
+ }
519
520
  }
520
521
 
521
522
  // Globals