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.
Files changed (188) hide show
  1. package/README.md +89 -119
  2. package/bin/codecept.js +53 -54
  3. package/docs/webapi/clearCookie.mustache +1 -1
  4. package/lib/actor.js +70 -102
  5. package/lib/ai.js +131 -121
  6. package/lib/assert/empty.js +11 -12
  7. package/lib/assert/equal.js +16 -21
  8. package/lib/assert/error.js +2 -2
  9. package/lib/assert/include.js +11 -15
  10. package/lib/assert/throws.js +3 -5
  11. package/lib/assert/truth.js +10 -7
  12. package/lib/assert.js +18 -18
  13. package/lib/codecept.js +112 -101
  14. package/lib/colorUtils.js +48 -50
  15. package/lib/command/check.js +206 -0
  16. package/lib/command/configMigrate.js +13 -14
  17. package/lib/command/definitions.js +24 -36
  18. package/lib/command/dryRun.js +16 -16
  19. package/lib/command/generate.js +38 -39
  20. package/lib/command/gherkin/init.js +36 -38
  21. package/lib/command/gherkin/snippets.js +76 -74
  22. package/lib/command/gherkin/steps.js +21 -18
  23. package/lib/command/info.js +49 -15
  24. package/lib/command/init.js +41 -37
  25. package/lib/command/interactive.js +22 -13
  26. package/lib/command/list.js +11 -10
  27. package/lib/command/run-multiple/chunk.js +50 -47
  28. package/lib/command/run-multiple/collection.js +5 -5
  29. package/lib/command/run-multiple/run.js +3 -3
  30. package/lib/command/run-multiple.js +27 -47
  31. package/lib/command/run-rerun.js +6 -7
  32. package/lib/command/run-workers.js +15 -66
  33. package/lib/command/run.js +8 -8
  34. package/lib/command/utils.js +22 -21
  35. package/lib/command/workers/runTests.js +131 -241
  36. package/lib/config.js +111 -49
  37. package/lib/container.js +589 -244
  38. package/lib/data/context.js +16 -18
  39. package/lib/data/dataScenarioConfig.js +9 -9
  40. package/lib/data/dataTableArgument.js +7 -7
  41. package/lib/data/table.js +6 -12
  42. package/lib/effects.js +307 -0
  43. package/lib/els.js +160 -0
  44. package/lib/event.js +24 -19
  45. package/lib/globals.js +141 -0
  46. package/lib/heal.js +89 -81
  47. package/lib/helper/AI.js +3 -2
  48. package/lib/helper/ApiDataFactory.js +19 -19
  49. package/lib/helper/Appium.js +47 -51
  50. package/lib/helper/FileSystem.js +35 -15
  51. package/lib/helper/GraphQL.js +1 -1
  52. package/lib/helper/GraphQLDataFactory.js +4 -4
  53. package/lib/helper/JSONResponse.js +72 -45
  54. package/lib/helper/Mochawesome.js +14 -11
  55. package/lib/helper/Playwright.js +832 -434
  56. package/lib/helper/Puppeteer.js +393 -292
  57. package/lib/helper/REST.js +32 -27
  58. package/lib/helper/WebDriver.js +320 -219
  59. package/lib/helper/errors/ConnectionRefused.js +6 -6
  60. package/lib/helper/errors/ElementAssertion.js +11 -16
  61. package/lib/helper/errors/ElementNotFound.js +5 -9
  62. package/lib/helper/errors/RemoteBrowserConnectionRefused.js +5 -5
  63. package/lib/helper/extras/Console.js +11 -11
  64. package/lib/helper/extras/PlaywrightLocator.js +110 -0
  65. package/lib/helper/extras/PlaywrightPropEngine.js +18 -18
  66. package/lib/helper/extras/PlaywrightRestartOpts.js +23 -23
  67. package/lib/helper/extras/Popup.js +22 -22
  68. package/lib/helper/extras/React.js +29 -30
  69. package/lib/helper/network/actions.js +33 -48
  70. package/lib/helper/network/utils.js +76 -83
  71. package/lib/helper/scripts/blurElement.js +6 -6
  72. package/lib/helper/scripts/focusElement.js +6 -6
  73. package/lib/helper/scripts/highlightElement.js +9 -9
  74. package/lib/helper/scripts/isElementClickable.js +34 -34
  75. package/lib/helper.js +2 -1
  76. package/lib/history.js +23 -20
  77. package/lib/hooks.js +10 -10
  78. package/lib/html.js +90 -100
  79. package/lib/index.js +48 -21
  80. package/lib/listener/config.js +8 -9
  81. package/lib/listener/emptyRun.js +54 -0
  82. package/lib/listener/exit.js +10 -12
  83. package/lib/listener/{retry.js → globalRetry.js} +10 -10
  84. package/lib/listener/globalTimeout.js +166 -0
  85. package/lib/listener/helpers.js +43 -24
  86. package/lib/listener/mocha.js +4 -5
  87. package/lib/listener/result.js +11 -0
  88. package/lib/listener/steps.js +26 -23
  89. package/lib/listener/store.js +20 -0
  90. package/lib/locator.js +213 -192
  91. package/lib/mocha/asyncWrapper.js +264 -0
  92. package/lib/mocha/bdd.js +167 -0
  93. package/lib/mocha/cli.js +341 -0
  94. package/lib/mocha/factory.js +160 -0
  95. package/lib/{interfaces → mocha}/featureConfig.js +33 -13
  96. package/lib/{interfaces → mocha}/gherkin.js +75 -45
  97. package/lib/mocha/hooks.js +121 -0
  98. package/lib/mocha/index.js +21 -0
  99. package/lib/mocha/inject.js +46 -0
  100. package/lib/{interfaces → mocha}/scenarioConfig.js +32 -8
  101. package/lib/mocha/suite.js +89 -0
  102. package/lib/mocha/test.js +178 -0
  103. package/lib/mocha/types.d.ts +42 -0
  104. package/lib/mocha/ui.js +229 -0
  105. package/lib/output.js +86 -64
  106. package/lib/parser.js +44 -44
  107. package/lib/pause.js +160 -139
  108. package/lib/plugin/analyze.js +403 -0
  109. package/lib/plugin/{autoLogin.js → auth.js} +137 -43
  110. package/lib/plugin/autoDelay.js +19 -15
  111. package/lib/plugin/coverage.js +22 -27
  112. package/lib/plugin/customLocator.js +5 -5
  113. package/lib/plugin/customReporter.js +53 -0
  114. package/lib/plugin/heal.js +49 -17
  115. package/lib/plugin/pageInfo.js +140 -0
  116. package/lib/plugin/pauseOnFail.js +4 -3
  117. package/lib/plugin/retryFailedStep.js +60 -19
  118. package/lib/plugin/screenshotOnFail.js +80 -83
  119. package/lib/plugin/stepByStepReport.js +70 -31
  120. package/lib/plugin/stepTimeout.js +7 -13
  121. package/lib/plugin/subtitles.js +10 -9
  122. package/lib/recorder.js +167 -126
  123. package/lib/rerun.js +94 -50
  124. package/lib/result.js +161 -0
  125. package/lib/secret.js +18 -17
  126. package/lib/session.js +95 -89
  127. package/lib/step/base.js +239 -0
  128. package/lib/step/comment.js +10 -0
  129. package/lib/step/config.js +50 -0
  130. package/lib/step/func.js +46 -0
  131. package/lib/step/helper.js +50 -0
  132. package/lib/step/meta.js +99 -0
  133. package/lib/step/record.js +74 -0
  134. package/lib/step/retry.js +11 -0
  135. package/lib/step/section.js +55 -0
  136. package/lib/step.js +18 -332
  137. package/lib/steps.js +54 -0
  138. package/lib/store.js +37 -5
  139. package/lib/template/heal.js +2 -11
  140. package/lib/timeout.js +60 -0
  141. package/lib/transform.js +8 -8
  142. package/lib/translation.js +32 -18
  143. package/lib/utils.js +354 -250
  144. package/lib/workerStorage.js +16 -16
  145. package/lib/workers.js +366 -282
  146. package/package.json +107 -95
  147. package/translations/de-DE.js +5 -4
  148. package/translations/fr-FR.js +5 -4
  149. package/translations/index.js +23 -9
  150. package/translations/it-IT.js +5 -4
  151. package/translations/ja-JP.js +5 -4
  152. package/translations/nl-NL.js +76 -0
  153. package/translations/pl-PL.js +5 -4
  154. package/translations/pt-BR.js +5 -4
  155. package/translations/ru-RU.js +5 -4
  156. package/translations/utils.js +18 -0
  157. package/translations/zh-CN.js +5 -4
  158. package/translations/zh-TW.js +5 -4
  159. package/typings/index.d.ts +177 -186
  160. package/typings/promiseBasedTypes.d.ts +3573 -5941
  161. package/typings/types.d.ts +4042 -6370
  162. package/lib/cli.js +0 -256
  163. package/lib/helper/ExpectHelper.js +0 -391
  164. package/lib/helper/Nightmare.js +0 -1504
  165. package/lib/helper/Protractor.js +0 -1863
  166. package/lib/helper/SoftExpectHelper.js +0 -381
  167. package/lib/helper/TestCafe.js +0 -1414
  168. package/lib/helper/clientscripts/nightmare.js +0 -213
  169. package/lib/helper/extras/PlaywrightReactVueLocator.js +0 -43
  170. package/lib/helper/testcafe/testControllerHolder.js +0 -42
  171. package/lib/helper/testcafe/testcafe-utils.js +0 -62
  172. package/lib/interfaces/bdd.js +0 -81
  173. package/lib/listener/artifacts.js +0 -19
  174. package/lib/listener/timeout.js +0 -109
  175. package/lib/mochaFactory.js +0 -113
  176. package/lib/plugin/allure.js +0 -15
  177. package/lib/plugin/commentStep.js +0 -136
  178. package/lib/plugin/debugErrors.js +0 -67
  179. package/lib/plugin/eachElement.js +0 -127
  180. package/lib/plugin/fakerTransform.js +0 -49
  181. package/lib/plugin/retryTo.js +0 -127
  182. package/lib/plugin/selenoid.js +0 -384
  183. package/lib/plugin/standardActingHelpers.js +0 -3
  184. package/lib/plugin/tryTo.js +0 -115
  185. package/lib/plugin/wdio.js +0 -249
  186. package/lib/scenario.js +0 -224
  187. package/lib/ui.js +0 -236
  188. package/lib/within.js +0 -70
@@ -0,0 +1,264 @@
1
+ import promiseRetry from 'promise-retry'
2
+ import event from '../event.js'
3
+ import recorder from '../recorder.js'
4
+ import assertThrown from '../assert/throws.js'
5
+ import { ucfirst, isAsyncFunction } from '../utils.js'
6
+ import { getInjectedArguments } from './inject.js'
7
+ import { fireHook } from './hooks.js'
8
+
9
+ const injectHook = function (inject, suite) {
10
+ try {
11
+ inject()
12
+ } catch (err) {
13
+ recorder.throw(err)
14
+ }
15
+ recorder.catch(err => {
16
+ suiteTestFailedHookError(suite, err)
17
+ throw err
18
+ })
19
+ return recorder.promise()
20
+ }
21
+
22
+ function suiteTestFailedHookError(suite, err, hookName) {
23
+ suite.eachTest(test => {
24
+ test.err = err
25
+ if (hookName) hookName = ucfirst(hookName)
26
+ event.emit(event.test.failed, test, err, hookName)
27
+ })
28
+ }
29
+
30
+ function makeDoneCallableOnce(done) {
31
+ let called = false
32
+ return function (err) {
33
+ if (called) {
34
+ return
35
+ }
36
+ called = true
37
+ return done(err)
38
+ }
39
+ }
40
+
41
+ /**
42
+ * Wraps test function, injects support objects from container,
43
+ * starts promise chain with recorder, performs before/after hooks
44
+ * through event system.
45
+ */
46
+ export function test(test) {
47
+ const testFn = test.fn
48
+ if (!testFn) {
49
+ return test
50
+ }
51
+
52
+ test.timeout(0)
53
+ test.async = true
54
+
55
+ test.fn = function (done) {
56
+ const doneFn = makeDoneCallableOnce(done)
57
+ recorder.errHandler(err => {
58
+ recorder.session.start('teardown')
59
+ recorder.cleanAsyncErr()
60
+ if (test.throws) {
61
+ // check that test should actually fail
62
+ try {
63
+ assertThrown(err, test.throws)
64
+ event.emit(event.test.passed, test)
65
+ event.emit(event.test.finished, test)
66
+ recorder.add(doneFn)
67
+ return
68
+ } catch (newErr) {
69
+ err = newErr
70
+ }
71
+ }
72
+ test.err = err
73
+ event.emit(event.test.failed, test, err)
74
+ event.emit(event.test.finished, test)
75
+ recorder.add(() => doneFn(err))
76
+ })
77
+
78
+ event.emit(event.test.started, test)
79
+
80
+ getInjectedArguments(testFn, test)
81
+ .then(args => {
82
+ // Start recorder to ensure any steps added within test function are executed
83
+ recorder.startUnlessRunning()
84
+
85
+ // Execute test function
86
+ const result = testFn.call(test, args)
87
+
88
+ // Wait for all recorder steps to complete
89
+ if (result && result.then) {
90
+ return result.then(() => recorder.promise())
91
+ }
92
+ return recorder.promise()
93
+ })
94
+ .then(() => {
95
+ recorder.add('fire test.passed', () => {
96
+ event.emit(event.test.passed, test)
97
+ event.emit(event.test.finished, test)
98
+ })
99
+ recorder.add('finish test', doneFn)
100
+ })
101
+ .catch(err => {
102
+ recorder.throw(err)
103
+ })
104
+ .finally(() => {
105
+ recorder.catch()
106
+ })
107
+ }
108
+ return test
109
+ }
110
+
111
+ /**
112
+ * Injects arguments to function from controller
113
+ */
114
+ export function injected(fn, suite, hookName) {
115
+ return function (done) {
116
+ const doneFn = makeDoneCallableOnce(done)
117
+ const errHandler = err => {
118
+ recorder.session.start('teardown')
119
+ recorder.cleanAsyncErr()
120
+ if (hookName == 'before' || hookName == 'beforeSuite') suiteTestFailedHookError(suite, err, hookName)
121
+ if (hookName === 'after') suite.eachTest(test => event.emit(event.test.after, test))
122
+ if (hookName === 'afterSuite') event.emit(event.suite.after, suite)
123
+ recorder.add(() => doneFn(err))
124
+ }
125
+
126
+ recorder.errHandler(err => {
127
+ errHandler(err)
128
+ })
129
+
130
+ if (!fn) throw new Error('fn is not defined')
131
+
132
+ fireHook(event.hook.started, suite)
133
+
134
+ this.test.body = fn.toString()
135
+
136
+ if (!recorder.isRunning()) {
137
+ recorder.errHandler(err => {
138
+ errHandler(err)
139
+ })
140
+ }
141
+
142
+ const opts = suite.opts || {}
143
+ const retries = opts[`retry${ucfirst(hookName)}`] || 0
144
+
145
+ const currentTest = hookName === 'before' || hookName === 'after' ? suite?.ctx?.currentTest : null
146
+
147
+ promiseRetry(
148
+ async (retry, number) => {
149
+ try {
150
+ recorder.startUnlessRunning()
151
+ const injectedArgs = await getInjectedArguments(fn, null, suite)
152
+ await fn.call(this, { ...injectedArgs, suite, test: currentTest })
153
+ await recorder.promise().catch(err => retry(err))
154
+ } catch (err) {
155
+ retry(err)
156
+ } finally {
157
+ if (number < retries) {
158
+ recorder.stop()
159
+ recorder.start()
160
+ }
161
+ }
162
+ },
163
+ { retries },
164
+ )
165
+ .then(() => {
166
+ recorder.add('fire hook.passed', () => fireHook(event.hook.passed, suite))
167
+ recorder.add('fire hook.finished', () => fireHook(event.hook.finished, suite))
168
+ recorder.add(`finish ${hookName} hook`, doneFn)
169
+ recorder.catch()
170
+ })
171
+ .catch(e => {
172
+ recorder.throw(e)
173
+ recorder.catch(e => {
174
+ const err = recorder.getAsyncErr() === null ? e : recorder.getAsyncErr()
175
+ errHandler(err)
176
+ })
177
+ recorder.add('fire hook.failed', () => fireHook(event.hook.failed, suite, e))
178
+ recorder.add('fire hook.finished', () => fireHook(event.hook.finished, suite))
179
+ })
180
+ }
181
+ }
182
+
183
+ /**
184
+ * Starts promise chain, so helpers could enqueue their hooks
185
+ */
186
+ export function setup(suite) {
187
+ return function (done) {
188
+ const doneFn = makeDoneCallableOnce(done)
189
+ recorder.startUnlessRunning()
190
+ import('./test.js').then(testModule => {
191
+ const { enhanceMochaTest } = testModule.default || testModule
192
+ event.emit(event.test.before, enhanceMochaTest(suite?.ctx?.currentTest))
193
+ recorder.add(() => doneFn())
194
+ })
195
+ }
196
+ }
197
+
198
+ export function teardown(suite) {
199
+ return function (done) {
200
+ const doneFn = makeDoneCallableOnce(done)
201
+ recorder.startUnlessRunning()
202
+ import('./test.js').then(testModule => {
203
+ const { enhanceMochaTest } = testModule.default || testModule
204
+ event.emit(event.test.after, enhanceMochaTest(suite?.ctx?.currentTest))
205
+ recorder.add(() => doneFn())
206
+ })
207
+ }
208
+ }
209
+
210
+ export function suiteSetup(suite) {
211
+ return function (done) {
212
+ const doneFn = makeDoneCallableOnce(done)
213
+ recorder.startUnlessRunning()
214
+
215
+ // Set up error handler for suite setup
216
+ recorder.errHandler(err => {
217
+ doneFn(err)
218
+ })
219
+
220
+ import('./suite.js')
221
+ .then(suiteModule => {
222
+ const { enhanceMochaSuite } = suiteModule.default || suiteModule
223
+ event.emit(event.suite.before, enhanceMochaSuite(suite))
224
+ recorder.add(() => doneFn())
225
+ })
226
+ .catch(err => {
227
+ doneFn(err)
228
+ })
229
+ }
230
+ }
231
+
232
+ export function suiteTeardown(suite) {
233
+ return function (done) {
234
+ const doneFn = makeDoneCallableOnce(done)
235
+ recorder.startUnlessRunning()
236
+
237
+ // Set up error handler for suite teardown
238
+ recorder.errHandler(err => {
239
+ doneFn(err)
240
+ })
241
+
242
+ import('./suite.js')
243
+ .then(suiteModule => {
244
+ const { enhanceMochaSuite } = suiteModule.default || suiteModule
245
+ event.emit(event.suite.after, enhanceMochaSuite(suite))
246
+ recorder.add(() => doneFn())
247
+ })
248
+ .catch(err => {
249
+ doneFn(err)
250
+ })
251
+ }
252
+ }
253
+
254
+ export { getInjectedArguments }
255
+
256
+ export default {
257
+ test,
258
+ injected,
259
+ setup,
260
+ teardown,
261
+ suiteSetup,
262
+ suiteTeardown,
263
+ getInjectedArguments,
264
+ }
@@ -0,0 +1,167 @@
1
+ import { CucumberExpression, ParameterTypeRegistry, ParameterType } from '@cucumber/cucumber-expressions'
2
+ import event from '../event.js'
3
+
4
+ let steps = {}
5
+ let Config
6
+
7
+ const STACK_POSITION = 2
8
+
9
+ async function getConfig() {
10
+ if (!Config) {
11
+ const ConfigModule = await import('../config.js')
12
+ Config = ConfigModule.default || ConfigModule
13
+ }
14
+ return Config
15
+ }
16
+
17
+ /**
18
+ * @param {*} step
19
+ * @param {*} fn
20
+ */
21
+ // Current file being loaded for step tracking
22
+ let currentStepFile = null
23
+
24
+ export function setCurrentStepFile(filePath) {
25
+ currentStepFile = filePath
26
+ }
27
+
28
+ export function clearCurrentStepFile() {
29
+ currentStepFile = null
30
+ }
31
+
32
+ const addStep = async (step, fn) => {
33
+ const config = await getConfig()
34
+ const avoidDuplicateSteps = config.get('gherkin', {}).avoidDuplicateSteps || false
35
+ if (avoidDuplicateSteps && steps[step]) {
36
+ throw new Error(`Step '${step}' is already defined`)
37
+ }
38
+ steps[step] = fn
39
+
40
+ // Use the current step file context if available (fallback for old usage)
41
+ if (currentStepFile) {
42
+ let relativePath = currentStepFile
43
+
44
+ // Remove any leading './' and keep step_definitions/ path
45
+ relativePath = relativePath.replace(/^\.\//, '').replace(/^.*\/(?=step_definitions)/, '')
46
+
47
+ fn.line = `${relativePath}:3:1`
48
+ } else {
49
+ fn.line = 'unknown_file:1:1'
50
+ }
51
+ }
52
+
53
+ const parameterTypeRegistry = new ParameterTypeRegistry()
54
+
55
+ const matchStep = step => {
56
+ for (const stepName in steps) {
57
+ if (stepName.indexOf('/') === 0) {
58
+ const regExpArr = stepName.match(/^\/(.*?)\/([gimy]*)$/) || []
59
+ const res = step.match(new RegExp(regExpArr[1], regExpArr[2]))
60
+ if (res) {
61
+ const fn = steps[stepName]
62
+ fn.params = res.slice(1)
63
+ return fn
64
+ }
65
+ continue
66
+ }
67
+ const expression = new CucumberExpression(stepName, parameterTypeRegistry)
68
+ const res = expression.match(step)
69
+ if (res) {
70
+ const fn = steps[stepName]
71
+ fn.params = res.map(arg => arg.getValue(null))
72
+ return fn
73
+ }
74
+ }
75
+ throw new Error(`No steps matching "${step.toString()}"`)
76
+ }
77
+
78
+ const clearSteps = () => {
79
+ steps = {}
80
+ }
81
+
82
+ const getSteps = () => {
83
+ return steps
84
+ }
85
+
86
+ const defineParameterType = options => {
87
+ const parameterType = buildParameterType(options)
88
+ parameterTypeRegistry.defineParameterType(parameterType)
89
+ }
90
+
91
+ const buildParameterType = ({ name, regexp, transformer, useForSnippets, preferForRegexpMatch }) => {
92
+ if (typeof useForSnippets !== 'boolean') useForSnippets = true
93
+ if (typeof preferForRegexpMatch !== 'boolean') preferForRegexpMatch = false
94
+ return new ParameterType(name, regexp, null, transformer, useForSnippets, preferForRegexpMatch)
95
+ }
96
+
97
+ // Create wrapper functions that capture the call context
98
+ const createStepFunction = stepType => {
99
+ return (step, fn) => {
100
+ // Capture the stack trace at the point where Given/When/Then is called
101
+ const callStack = new Error().stack
102
+
103
+ // Find the caller (step definition file) in the stack
104
+ let callerInfo = 'unknown_file:1:1'
105
+ if (callStack) {
106
+ const stackLines = callStack.split('\n')
107
+ for (let i = 1; i < stackLines.length; i++) {
108
+ const line = stackLines[i]
109
+ if (line.includes('step_definitions') && (line.includes('.js') || line.includes('.mjs'))) {
110
+ // Extract file path and use line 3:1 as consistent reference (import line)
111
+ const match = line.match(/file:\/\/.*\/(step_definitions\/[^:]+):(\d+):(\d+)/)
112
+ if (match) {
113
+ callerInfo = `${match[1]}:3:1` // Use line 3:1 consistently (import line)
114
+ break
115
+ }
116
+ }
117
+ }
118
+ }
119
+
120
+ // Instead of using global currentStepFile, pass the caller info directly to addStep
121
+ return addStepWithCaller(step, fn, callerInfo)
122
+ }
123
+ }
124
+
125
+ // New function that accepts caller info directly
126
+ const addStepWithCaller = async (step, fn, callerInfo) => {
127
+ const config = await getConfig()
128
+ const avoidDuplicateSteps = config.get('gherkin', {}).avoidDuplicateSteps || false
129
+ if (avoidDuplicateSteps && steps[step]) {
130
+ throw new Error(`Step '${step}' is already defined`)
131
+ }
132
+ steps[step] = fn
133
+
134
+ // Use the caller info passed directly
135
+ fn.line = callerInfo
136
+ }
137
+
138
+ const Given = createStepFunction('Given')
139
+ const When = createStepFunction('When')
140
+ const Then = createStepFunction('Then')
141
+ const And = createStepFunction('And')
142
+
143
+ // Before/After hooks for BDD - these are global event listeners
144
+ const Before = fn => {
145
+ event.dispatcher.on(event.test.started, fn)
146
+ }
147
+
148
+ const After = fn => {
149
+ event.dispatcher.on(event.test.finished, fn)
150
+ }
151
+
152
+ const Fail = fn => {
153
+ event.dispatcher.on(event.test.failed, fn)
154
+ }
155
+
156
+ export { Given, When, Then, And, Before, After, Fail, matchStep, getSteps, clearSteps, defineParameterType }
157
+
158
+ export default {
159
+ Given: addStep,
160
+ When: addStep,
161
+ Then: addStep,
162
+ And: addStep,
163
+ matchStep,
164
+ getSteps,
165
+ clearSteps,
166
+ defineParameterType,
167
+ }