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.
Files changed (105) hide show
  1. package/README.md +81 -110
  2. package/bin/codecept.js +2 -2
  3. package/docs/webapi/clearCookie.mustache +1 -1
  4. package/lib/actor.js +46 -36
  5. package/lib/assert/empty.js +3 -5
  6. package/lib/assert/equal.js +4 -7
  7. package/lib/assert/include.js +4 -6
  8. package/lib/assert/throws.js +2 -4
  9. package/lib/assert/truth.js +2 -2
  10. package/lib/codecept.js +87 -83
  11. package/lib/command/configMigrate.js +2 -4
  12. package/lib/command/definitions.js +5 -25
  13. package/lib/command/generate.js +10 -14
  14. package/lib/command/gherkin/snippets.js +10 -8
  15. package/lib/command/gherkin/steps.js +1 -1
  16. package/lib/command/info.js +1 -3
  17. package/lib/command/init.js +8 -12
  18. package/lib/command/interactive.js +1 -1
  19. package/lib/command/list.js +1 -1
  20. package/lib/command/run-multiple.js +12 -35
  21. package/lib/command/run-workers.js +10 -10
  22. package/lib/command/utils.js +5 -6
  23. package/lib/command/workers/runTests.js +14 -17
  24. package/lib/container.js +327 -237
  25. package/lib/data/context.js +10 -13
  26. package/lib/data/dataScenarioConfig.js +8 -8
  27. package/lib/data/dataTableArgument.js +6 -6
  28. package/lib/data/table.js +5 -11
  29. package/lib/els.js +177 -0
  30. package/lib/event.js +1 -0
  31. package/lib/heal.js +78 -80
  32. package/lib/helper/ApiDataFactory.js +3 -6
  33. package/lib/helper/Appium.js +15 -30
  34. package/lib/helper/FileSystem.js +3 -3
  35. package/lib/helper/GraphQLDataFactory.js +3 -3
  36. package/lib/helper/JSONResponse.js +57 -37
  37. package/lib/helper/Nightmare.js +35 -53
  38. package/lib/helper/Playwright.js +189 -251
  39. package/lib/helper/Protractor.js +54 -77
  40. package/lib/helper/Puppeteer.js +134 -232
  41. package/lib/helper/REST.js +5 -17
  42. package/lib/helper/TestCafe.js +21 -44
  43. package/lib/helper/WebDriver.js +103 -162
  44. package/lib/helper/testcafe/testcafe-utils.js +26 -27
  45. package/lib/listener/artifacts.js +2 -2
  46. package/lib/listener/emptyRun.js +58 -0
  47. package/lib/listener/exit.js +4 -4
  48. package/lib/listener/{retry.js → globalRetry.js} +5 -5
  49. package/lib/listener/{timeout.js → globalTimeout.js} +8 -8
  50. package/lib/listener/helpers.js +15 -15
  51. package/lib/listener/mocha.js +1 -1
  52. package/lib/listener/steps.js +17 -12
  53. package/lib/listener/store.js +12 -0
  54. package/lib/mocha/asyncWrapper.js +204 -0
  55. package/lib/{interfaces → mocha}/bdd.js +3 -3
  56. package/lib/mocha/cli.js +257 -0
  57. package/lib/mocha/factory.js +104 -0
  58. package/lib/{interfaces → mocha}/featureConfig.js +11 -12
  59. package/lib/{interfaces → mocha}/gherkin.js +26 -28
  60. package/lib/mocha/hooks.js +83 -0
  61. package/lib/mocha/index.js +12 -0
  62. package/lib/mocha/inject.js +24 -0
  63. package/lib/{interfaces → mocha}/scenarioConfig.js +10 -6
  64. package/lib/mocha/suite.js +55 -0
  65. package/lib/mocha/test.js +60 -0
  66. package/lib/mocha/types.d.ts +31 -0
  67. package/lib/mocha/ui.js +219 -0
  68. package/lib/output.js +28 -10
  69. package/lib/pause.js +159 -135
  70. package/lib/plugin/autoDelay.js +4 -4
  71. package/lib/plugin/autoLogin.js +6 -7
  72. package/lib/plugin/commentStep.js +1 -1
  73. package/lib/plugin/coverage.js +10 -19
  74. package/lib/plugin/customLocator.js +3 -3
  75. package/lib/plugin/debugErrors.js +2 -2
  76. package/lib/plugin/eachElement.js +1 -1
  77. package/lib/plugin/fakerTransform.js +1 -1
  78. package/lib/plugin/heal.js +6 -9
  79. package/lib/plugin/retryFailedStep.js +4 -4
  80. package/lib/plugin/retryTo.js +2 -2
  81. package/lib/plugin/screenshotOnFail.js +9 -36
  82. package/lib/plugin/selenoid.js +15 -35
  83. package/lib/plugin/stepByStepReport.js +51 -13
  84. package/lib/plugin/stepTimeout.js +4 -11
  85. package/lib/plugin/subtitles.js +4 -4
  86. package/lib/plugin/tryTo.js +1 -1
  87. package/lib/plugin/wdio.js +8 -10
  88. package/lib/recorder.js +142 -121
  89. package/lib/secret.js +1 -1
  90. package/lib/step.js +160 -144
  91. package/lib/store.js +6 -2
  92. package/lib/template/heal.js +2 -11
  93. package/lib/utils.js +224 -216
  94. package/lib/within.js +73 -55
  95. package/lib/workers.js +265 -261
  96. package/package.json +46 -47
  97. package/typings/index.d.ts +172 -184
  98. package/typings/promiseBasedTypes.d.ts +53 -516
  99. package/typings/types.d.ts +127 -587
  100. package/lib/cli.js +0 -256
  101. package/lib/helper/ExpectHelper.js +0 -391
  102. package/lib/helper/SoftExpectHelper.js +0 -381
  103. package/lib/mochaFactory.js +0 -113
  104. package/lib/scenario.js +0 -224
  105. package/lib/ui.js +0 -236
@@ -0,0 +1,24 @@
1
+ const parser = require('../parser')
2
+
3
+ const getInjectedArguments = (fn, test) => {
4
+ const container = require('../container')
5
+ const testArgs = {}
6
+ const params = parser.getParams(fn) || []
7
+ const objects = container.support()
8
+ for (const key of params) {
9
+ testArgs[key] = {}
10
+ if (test && test.inject && test.inject[key]) {
11
+ // @FIX: need fix got inject
12
+ testArgs[key] = test.inject[key]
13
+ continue
14
+ }
15
+ if (!objects[key]) {
16
+ throw new Error(`Object of type ${key} is not defined in container`)
17
+ }
18
+ testArgs[key] = container.support(key)
19
+ }
20
+
21
+ return testArgs
22
+ }
23
+
24
+ module.exports.getInjectedArguments = getInjectedArguments
@@ -1,3 +1,5 @@
1
+ const { isAsyncFunction } = require('../utils')
2
+
1
3
  /** @class */
2
4
  class ScenarioConfig {
3
5
  constructor(test) {
@@ -71,17 +73,19 @@ class ScenarioConfig {
71
73
  * @param {Object<string, any>} [obj]
72
74
  * @returns {this}
73
75
  */
74
- async config(helper, obj) {
76
+ config(helper, obj) {
75
77
  if (!obj) {
76
78
  obj = helper
77
79
  helper = 0
78
80
  }
79
81
  if (typeof obj === 'function') {
80
- obj = await obj(this.test)
81
- }
82
- if (!this.test.config) {
83
- this.test.config = {}
82
+ if (isAsyncFunction(obj)) {
83
+ obj(this.test).then(res => (this.test.config[helper] = res))
84
+ return this
85
+ }
86
+ obj = obj(this.test)
84
87
  }
88
+
85
89
  this.test.config[helper] = obj
86
90
  return this
87
91
  }
@@ -104,7 +108,7 @@ class ScenarioConfig {
104
108
  * @returns {this}
105
109
  */
106
110
  injectDependencies(dependencies) {
107
- Object.keys(dependencies).forEach((key) => {
111
+ Object.keys(dependencies).forEach(key => {
108
112
  this.test.inject[key] = dependencies[key]
109
113
  })
110
114
  return this
@@ -0,0 +1,55 @@
1
+ const MochaSuite = require('mocha/lib/suite')
2
+
3
+ /**
4
+ * @typedef {import('mocha')} Mocha
5
+ */
6
+
7
+ /**
8
+ * Enhances MochaSuite with CodeceptJS specific functionality using composition
9
+ */
10
+ function enhanceMochaSuite(suite) {
11
+ // already enhanced
12
+ if (suite.codeceptjs) return suite
13
+
14
+ suite.codeceptjs = true
15
+ // Add properties
16
+ suite.tags = suite.title.match(/(\@[a-zA-Z0-9-_]+)/g) || []
17
+ suite.opts = {}
18
+ // suite.totalTimeout = undefined
19
+
20
+ // Override fullTitle method
21
+ suite.fullTitle = () => `${suite.title}:`
22
+
23
+ // Add new methods
24
+ suite.applyOptions = function (opts) {
25
+ if (!opts) opts = {}
26
+ suite.opts = opts
27
+
28
+ if (opts.retries) suite.retries(opts.retries)
29
+ if (opts.timeout) suite.totalTimeout = opts.timeout
30
+
31
+ if (opts.skipInfo && opts.skipInfo.skipped) {
32
+ suite.pending = true
33
+ suite.opts = { ...this.opts, skipInfo: opts.skipInfo }
34
+ }
35
+ }
36
+
37
+ return suite
38
+ }
39
+
40
+ /**
41
+ * Factory function to create enhanced suites
42
+ * @param {Mocha.Suite} parent - Parent suite
43
+ * @param {string} title - Suite title
44
+ * @returns {CodeceptJS.Suite & Mocha.Suite} New enhanced suite instance
45
+ */
46
+ function createSuite(parent, title) {
47
+ const suite = MochaSuite.create(parent, title)
48
+ suite.timeout(0)
49
+ return enhanceMochaSuite(suite)
50
+ }
51
+
52
+ module.exports = {
53
+ createSuite,
54
+ enhanceMochaSuite,
55
+ }
@@ -0,0 +1,60 @@
1
+ const Test = require('mocha/lib/test')
2
+ const { test: testWrapper } = require('./asyncWrapper')
3
+ const { enhanceMochaSuite } = require('./suite')
4
+ const { genTestId } = require('../utils')
5
+
6
+ /**
7
+ * Factory function to create enhanced tests
8
+ * @param {string} title - Test title
9
+ * @param {Function} fn - Test function
10
+ * @returns {CodeceptJS.Test & Mocha.Test} New enhanced test instance
11
+ */
12
+ function createTest(title, fn) {
13
+ const test = new Test(title, fn)
14
+ return enhanceMochaTest(test)
15
+ }
16
+
17
+ /**
18
+ * Enhances Mocha Test with CodeceptJS specific functionality using composition
19
+ * @param {CodeceptJS.Test & Mocha.Test} test - Test instance to enhance
20
+ * @returns {CodeceptJS.Test & Mocha.Test} Enhanced test instance
21
+ */
22
+ function enhanceMochaTest(test) {
23
+ // already enhanced
24
+ if (test.codeceptjs) return test
25
+
26
+ test.codeceptjs = true
27
+ // Add properties
28
+ test.tags = test.title.match(/(\@[a-zA-Z0-9-_]+)/g) || []
29
+ test.steps = []
30
+ test.config = {}
31
+ test.artifacts = []
32
+ test.inject = {}
33
+ test.opts = {}
34
+
35
+ // Add new methods
36
+ /**
37
+ * @param {Mocha.Suite} suite - The Mocha suite to add this test to
38
+ */
39
+ test.addToSuite = function (suite) {
40
+ enhanceMochaSuite(suite)
41
+ suite.addTest(testWrapper(this))
42
+ test.tags = [...(test.tags || []), ...(suite.tags || [])]
43
+ test.fullTitle = () => `${suite.title}: ${test.title}`
44
+ test.uid = genTestId(test)
45
+ }
46
+
47
+ test.applyOptions = function (opts) {
48
+ if (!opts) opts = {}
49
+ test.opts = opts
50
+ test.totalTimeout = opts.timeout
51
+ if (opts.retries) this.retries(opts.retries)
52
+ }
53
+
54
+ return test
55
+ }
56
+
57
+ module.exports = {
58
+ createTest,
59
+ enhanceMochaTest,
60
+ }
@@ -0,0 +1,31 @@
1
+ import { Test as MochaTest, Suite as MochaSuite } from 'mocha'
2
+
3
+ declare global {
4
+ namespace CodeceptJS {
5
+ interface Test extends MochaTest {
6
+ uid: string
7
+ title: string
8
+ tags: string[]
9
+ steps: string[]
10
+ config: Record<string, any>
11
+ artifacts: string[]
12
+ inject: Record<string, any>
13
+ opts: Record<string, any>
14
+ throws?: Error | string | RegExp | Function
15
+ totalTimeout?: number
16
+ addToSuite(suite: Mocha.Suite): void
17
+ applyOptions(opts: Record<string, any>): void
18
+ codeceptjs: boolean
19
+ }
20
+
21
+ interface Suite extends MochaSuite {
22
+ title: string
23
+ tags: string[]
24
+ opts: Record<string, any>
25
+ totalTimeout?: number
26
+ addTest(test: Test): void
27
+ applyOptions(opts: Record<string, any>): void
28
+ codeceptjs: boolean
29
+ }
30
+ }
31
+ }
@@ -0,0 +1,219 @@
1
+ const escapeRe = require('escape-string-regexp')
2
+ const { test, setup, teardown, suiteSetup, suiteTeardown, injected } = require('./asyncWrapper')
3
+ const ScenarioConfig = require('./scenarioConfig')
4
+ const FeatureConfig = require('./featureConfig')
5
+ const addDataContext = require('../data/context')
6
+ const { createTest } = require('./test')
7
+ const { createSuite } = require('./suite')
8
+ const { HookConfig, AfterSuiteHook, AfterHook, BeforeSuiteHook, BeforeHook } = require('./hooks')
9
+
10
+ const setContextTranslation = context => {
11
+ const container = require('../container')
12
+ const contexts = container.translation().value('contexts')
13
+
14
+ if (contexts) {
15
+ for (const key of Object.keys(contexts)) {
16
+ if (context[key]) {
17
+ context[contexts[key]] = context[key]
18
+ }
19
+ }
20
+ }
21
+ }
22
+
23
+ /**
24
+ * Codecept-style interface:
25
+ *
26
+ * Feature('login');
27
+ *
28
+ * Scenario('login as regular user', ({I}) {
29
+ * I.fillField();
30
+ * I.click();
31
+ * I.see('Hello, '+data.login);
32
+ * });
33
+ *
34
+ * @param {Mocha.Suite} suite Root suite.
35
+ * @ignore
36
+ */
37
+ module.exports = function (suite) {
38
+ const suites = [suite]
39
+ suite.timeout(0)
40
+ let afterAllHooks
41
+ let afterEachHooks
42
+ let afterAllHooksAreLoaded
43
+ let afterEachHooksAreLoaded
44
+
45
+ suite.on('pre-require', (context, file, mocha) => {
46
+ const common = require('mocha/lib/interfaces/common')(suites, context, mocha)
47
+
48
+ const addScenario = function (title, opts = {}, fn) {
49
+ const suite = suites[0]
50
+
51
+ if (typeof opts === 'function' && !fn) {
52
+ fn = opts
53
+ opts = {}
54
+ }
55
+ if (suite.pending) {
56
+ fn = null
57
+ }
58
+ const test = createTest(title, fn)
59
+ test.file = file
60
+ test.addToSuite(suite)
61
+ test.applyOptions(opts)
62
+
63
+ return new ScenarioConfig(test)
64
+ }
65
+
66
+ // create dispatcher
67
+
68
+ context.BeforeAll = common.before
69
+ context.AfterAll = common.after
70
+
71
+ context.run = mocha.options.delay && common.runWithSuite(suite)
72
+ /**
73
+ * Describe a "suite" with the given `title`
74
+ * and callback `fn` containing nested suites
75
+ * and/or tests.
76
+ * @global
77
+ * @param {string} title
78
+ * @param {Object<string, *>} [opts]
79
+ * @returns {FeatureConfig}
80
+ */
81
+
82
+ context.Feature = function (title, opts) {
83
+ if (suites.length > 1) {
84
+ suites.shift()
85
+ }
86
+
87
+ afterAllHooks = []
88
+ afterEachHooks = []
89
+ afterAllHooksAreLoaded = false
90
+ afterEachHooksAreLoaded = false
91
+
92
+ const suite = createSuite(suites[0], title)
93
+ suite.applyOptions(opts)
94
+
95
+ suite.file = file
96
+ suites.unshift(suite)
97
+ suite.beforeEach('codeceptjs.before', () => setup(suite))
98
+ afterEachHooks.push(['finalize codeceptjs', () => teardown(suite)])
99
+
100
+ suite.beforeAll('codeceptjs.beforeSuite', () => suiteSetup(suite))
101
+ afterAllHooks.push(['codeceptjs.afterSuite', () => suiteTeardown(suite)])
102
+
103
+ return new FeatureConfig(suite)
104
+ }
105
+
106
+ /**
107
+ * Pending test suite.
108
+ * @global
109
+ * @kind constant
110
+ * @type {CodeceptJS.IFeature}
111
+ */
112
+ context.xFeature = context.Feature.skip = function (title, opts) {
113
+ const skipInfo = {
114
+ skipped: true,
115
+ message: 'Skipped due to "skip" on Feature.',
116
+ }
117
+ return context.Feature(title, { ...opts, skipInfo })
118
+ }
119
+
120
+ context.BeforeSuite = function (fn) {
121
+ suites[0].beforeAll('BeforeSuite', injected(fn, suites[0], 'beforeSuite'))
122
+ return new HookConfig(new BeforeSuiteHook({ suite: suites[0] }))
123
+ }
124
+
125
+ context.AfterSuite = function (fn) {
126
+ afterAllHooks.unshift(['AfterSuite', injected(fn, suites[0], 'afterSuite')])
127
+ return new HookConfig(new AfterSuiteHook({ suite: suites[0] }))
128
+ }
129
+
130
+ context.Background = context.Before = function (fn) {
131
+ suites[0].beforeEach('Before', injected(fn, suites[0], 'before'))
132
+ return new HookConfig(new BeforeHook({ suite: suites[0] }))
133
+ }
134
+
135
+ context.After = function (fn) {
136
+ afterEachHooks.unshift(['After', injected(fn, suites[0], 'after')])
137
+ return new HookConfig(new AfterHook({ suite: suites[0] }))
138
+ }
139
+
140
+ /**
141
+ * Describe a specification or test-case
142
+ * with the given `title` and callback `fn`
143
+ * acting as a thunk.
144
+ * @ignore
145
+ */
146
+ context.Scenario = addScenario
147
+ /**
148
+ * Exclusive test-case.
149
+ * @ignore
150
+ */
151
+ context.Scenario.only = function (title, opts, fn) {
152
+ const reString = `^${escapeRe(`${suites[0].title}: ${title}`.replace(/( \| {.+})?$/g, ''))}`
153
+ mocha.grep(new RegExp(reString))
154
+ process.env.SCENARIO_ONLY = true
155
+ return addScenario(title, opts, fn)
156
+ }
157
+
158
+ /**
159
+ * Pending test case.
160
+ * @global
161
+ * @kind constant
162
+ * @type {CodeceptJS.IScenario}
163
+ */
164
+ context.xScenario = context.Scenario.skip = function (title, opts = {}, fn) {
165
+ if (typeof opts === 'function' && !fn) {
166
+ opts = {}
167
+ }
168
+
169
+ return context.Scenario(title, opts)
170
+ }
171
+
172
+ /**
173
+ * Pending test case with message: 'Test not implemented!'.
174
+ * @global
175
+ * @kind constant
176
+ * @type {CodeceptJS.IScenario}
177
+ */
178
+ context.Scenario.todo = function (title, opts = {}, fn) {
179
+ if (typeof opts === 'function' && !fn) {
180
+ fn = opts
181
+ opts = {}
182
+ }
183
+
184
+ const skipInfo = {
185
+ message: 'Test not implemented!',
186
+ description: fn ? fn.toString() : '',
187
+ }
188
+
189
+ return context.Scenario(title, { ...opts, skipInfo })
190
+ }
191
+
192
+ /**
193
+ * For translation
194
+ */
195
+
196
+ setContextTranslation(context)
197
+
198
+ addDataContext(context)
199
+ })
200
+
201
+ suite.on('post-require', () => {
202
+ /**
203
+ * load hooks from arrays to suite to prevent reordering
204
+ */
205
+ if (!afterEachHooksAreLoaded && Array.isArray(afterEachHooks)) {
206
+ afterEachHooks.forEach(hook => {
207
+ suites[0].afterEach(hook[0], hook[1])
208
+ })
209
+ afterEachHooksAreLoaded = true
210
+ }
211
+
212
+ if (!afterAllHooksAreLoaded && Array.isArray(afterAllHooks)) {
213
+ afterAllHooks.forEach(hook => {
214
+ suites[0].afterAll(hook[0], hook[1])
215
+ })
216
+ afterAllHooksAreLoaded = true
217
+ }
218
+ })
219
+ }
package/lib/output.js CHANGED
@@ -1,6 +1,6 @@
1
1
  const colors = require('chalk');
2
2
  const figures = require('figures');
3
- const { maskSensitiveData } = require('invisi-data')
3
+ const { maskSensitiveData } = require('invisi-data');
4
4
 
5
5
  const styles = {
6
6
  error: colors.bgRed.white.bold,
@@ -48,7 +48,7 @@ module.exports = {
48
48
  * @returns {string}
49
49
  */
50
50
  process(process) {
51
- if (process === null) return outputProcess = '';
51
+ if (process === null) return (outputProcess = '');
52
52
  if (process) outputProcess = String(process).length === 1 ? `[0${process}]` : `[${process}]`;
53
53
  return outputProcess;
54
54
  },
@@ -58,7 +58,7 @@ module.exports = {
58
58
  * @param {string} msg
59
59
  */
60
60
  debug(msg) {
61
- const _msg = isMaskedData() ? maskSensitiveData(msg) : msg
61
+ const _msg = isMaskedData() ? maskSensitiveData(msg) : msg;
62
62
  if (outputLevel >= 2) {
63
63
  print(' '.repeat(this.stepShift), styles.debug(`${figures.pointerSmall} ${_msg}`));
64
64
  }
@@ -69,7 +69,7 @@ module.exports = {
69
69
  * @param {string} msg
70
70
  */
71
71
  log(msg) {
72
- const _msg = isMaskedData() ? maskSensitiveData(msg) : msg
72
+ const _msg = isMaskedData() ? maskSensitiveData(msg) : msg;
73
73
  if (outputLevel >= 3) {
74
74
  print(' '.repeat(this.stepShift), styles.log(truncate(` ${_msg}`, this.spaceShift)));
75
75
  }
@@ -114,16 +114,16 @@ module.exports = {
114
114
  }
115
115
  }
116
116
 
117
- let stepLine = step.toString();
117
+ let stepLine = step.toCliStyled();
118
118
  if (step.metaStep && outputLevel >= 1) {
119
119
  // this.stepShift += 2;
120
- stepLine = colors.green(truncate(stepLine, this.spaceShift));
120
+ stepLine = colors.dim(truncate(stepLine, this.spaceShift));
121
121
  }
122
122
  if (step.comment) {
123
123
  stepLine += colors.grey(step.comment.split('\n').join('\n' + ' '.repeat(4)));
124
124
  }
125
125
 
126
- const _stepLine = isMaskedData() ? maskSensitiveData(stepLine) : stepLine
126
+ const _stepLine = isMaskedData() ? maskSensitiveData(stepLine) : stepLine;
127
127
  print(' '.repeat(this.stepShift), truncate(_stepLine, this.spaceShift));
128
128
  },
129
129
 
@@ -132,7 +132,7 @@ module.exports = {
132
132
  /**
133
133
  * @param {Mocha.Suite} suite
134
134
  */
135
- started: (suite) => {
135
+ started: suite => {
136
136
  if (!suite.title) return;
137
137
  print(`${colors.bold(suite.title)} --`);
138
138
  if (suite.comment) print(suite.comment);
@@ -173,7 +173,10 @@ module.exports = {
173
173
  * @param {Mocha.Test} test
174
174
  */
175
175
 
176
- started(test) {},
176
+ started(test) {
177
+ if (outputLevel < 1) return;
178
+ print(` ${colors.dim.bold('Scenario()')}`);
179
+ },
177
180
 
178
181
  /**
179
182
  * @param {Mocha.Test} test
@@ -191,6 +194,21 @@ module.exports = {
191
194
  },
192
195
  },
193
196
 
197
+ hook: {
198
+ started(hook) {
199
+ if (outputLevel < 1) return;
200
+ print(` ${colors.dim.bold(hook.toCode())}`);
201
+ },
202
+ passed(hook) {
203
+ if (outputLevel < 1) return;
204
+ print();
205
+ },
206
+ failed(hook) {
207
+ if (outputLevel < 1) return;
208
+ print(` ${colors.red.bold(hook.toCode())}`);
209
+ },
210
+ },
211
+
194
212
  /**
195
213
  *
196
214
  * Print a text in console log
@@ -260,5 +278,5 @@ function truncate(msg, gap = 0) {
260
278
  }
261
279
 
262
280
  function isMaskedData() {
263
- return global.maskSensitiveData === true || false
281
+ return global.maskSensitiveData === true || false;
264
282
  }