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,178 @@
1
+ import Test from 'mocha/lib/test.js'
2
+ import Suite from 'mocha/lib/suite.js'
3
+ import { genTestId, serializeError, clearString, relativeDir } from '../utils.js'
4
+ import Step from '../step/base.js'
5
+ import { enhanceMochaSuite } from './suite.js'
6
+ import { test as testWrapper } from './asyncWrapper.js'
7
+ /**
8
+ * Factory function to create enhanced tests
9
+ * @param {string} title - Test title
10
+ * @param {Function} fn - Test function
11
+ * @returns {CodeceptJS.Test & Mocha.Test} New enhanced test instance
12
+ */
13
+ function createTest(title, fn) {
14
+ const test = new Test(title, fn)
15
+ return enhanceMochaTest(test)
16
+ }
17
+
18
+ /**
19
+ * Enhances Mocha Test with CodeceptJS specific functionality using composition
20
+ * @param {CodeceptJS.Test & Mocha.Test} test - Test instance to enhance
21
+ * @returns {CodeceptJS.Test & Mocha.Test} Enhanced test instance
22
+ */
23
+ function enhanceMochaTest(test) {
24
+ // if no test, create a dummy one
25
+ if (!test) test = createTest('...', () => {})
26
+ // already enhanced
27
+ if (test.codeceptjs) return test
28
+
29
+ test.codeceptjs = true
30
+ // Add properties
31
+ test.tags = test.title.match(/(\@[a-zA-Z0-9-_]+)/g) || []
32
+ test.steps = []
33
+ test.config = {}
34
+ test.artifacts = []
35
+ test.inject = {}
36
+ test.opts = {}
37
+ test.meta = {}
38
+
39
+ test.notes = []
40
+ test.addNote = (type, note) => {
41
+ test.notes.push({ type, text: note })
42
+ }
43
+
44
+ // Add new methods
45
+ /**
46
+ * @param {Mocha.Suite} suite - The Mocha suite to add this test to
47
+ */
48
+ test.addToSuite = function (suite) {
49
+ enhanceMochaSuite(suite)
50
+ // Get testWrapper from asyncWrapper module
51
+ suite.addTest(testWrapper(this))
52
+ if (test.file && !suite.file) suite.file = test.file
53
+ test.tags = [...(test.tags || []), ...(suite.tags || [])]
54
+ test.fullTitle = () => `${suite.title}: ${test.title}`
55
+ test.uid = genTestId(test)
56
+ }
57
+
58
+ test.applyOptions = function (opts) {
59
+ if (!opts) opts = {}
60
+ test.opts = opts
61
+ test.meta = opts.meta || {}
62
+ test.totalTimeout = opts.timeout
63
+ if (opts.retries) this.retries(opts.retries)
64
+ }
65
+
66
+ test.simplify = function () {
67
+ return serializeTest(this)
68
+ }
69
+
70
+ return test
71
+ }
72
+
73
+ function deserializeTest(test) {
74
+ test = Object.assign(
75
+ createTest(test.title || '', () => {}),
76
+ test,
77
+ )
78
+ test.parent = Object.assign(new Suite(test.parent?.title || 'Suite'), test.parent)
79
+ enhanceMochaSuite(test.parent)
80
+ if (test.steps) test.steps = test.steps.map(step => Object.assign(new Step(step.title), step))
81
+ return test
82
+ }
83
+
84
+ function serializeTest(test, error = null) {
85
+ // test = { ...test }
86
+
87
+ if (test.start && !test.duration) {
88
+ const end = +new Date()
89
+ test.duration = end - test.start
90
+ }
91
+
92
+ let err
93
+
94
+ if (test.err) {
95
+ err = serializeError(test.err)
96
+ test.state = 'failed'
97
+ } else if (error) {
98
+ err = serializeError(error)
99
+ test.state = 'failed'
100
+ }
101
+ const parent = {}
102
+ if (test.parent) {
103
+ parent.title = test.parent.title
104
+ }
105
+
106
+ if (test.opts) {
107
+ Object.keys(test.opts).forEach(k => {
108
+ if (typeof test.opts[k] === 'object') delete test.opts[k]
109
+ if (typeof test.opts[k] === 'function') delete test.opts[k]
110
+ })
111
+ }
112
+
113
+ let steps = undefined
114
+ if (Array.isArray(test.steps)) {
115
+ steps = test.steps.map(step => (step.simplify ? step.simplify() : step))
116
+ }
117
+
118
+ return {
119
+ opts: test.opts || {},
120
+ tags: test.tags || [],
121
+ uid: test.uid,
122
+ retries: test._retries,
123
+ title: test.title,
124
+ state: test.state,
125
+ notes: test.notes || [],
126
+ meta: test.meta || {},
127
+ artifacts: test.artifacts || {},
128
+ duration: test.duration || 0,
129
+ err,
130
+ parent,
131
+ steps,
132
+ }
133
+ }
134
+
135
+ function cloneTest(test) {
136
+ return deserializeTest(serializeTest(test))
137
+ }
138
+
139
+ /**
140
+ * Get a filename from the test object
141
+ * @param {CodeceptJS.Test} test
142
+ * @param {Object} options
143
+ * @param {string} options.suffix Add a suffix to the filename
144
+ * @param {boolean} options.unique Add a unique suffix to the file
145
+ *
146
+ * @returns {string} the filename
147
+ */
148
+ function testToFileName(test, { suffix = '', unique = false } = {}) {
149
+ let fileName = test.title
150
+
151
+ if (unique) fileName = `${fileName}_${test?.uid || Math.floor(new Date().getTime() / 1000)}`
152
+ if (suffix) fileName = `${fileName}_${suffix}`
153
+ // remove tags with empty string (disable for now)
154
+ // fileName = fileName.replace(/\@\w+/g, '')
155
+ fileName = fileName.slice(0, 100)
156
+ if (fileName.indexOf('{') !== -1) {
157
+ fileName = fileName.substr(0, fileName.indexOf('{') - 3).trim()
158
+ }
159
+ if (test.ctx && test.ctx.test && test.ctx.test.type === 'hook') fileName = clearString(`${test.title}_${test.ctx.test.title}`)
160
+ // TODO: add suite title to file name
161
+ // if (test.parent && test.parent.title) {
162
+ // fileName = `${clearString(test.parent.title)}_${fileName}`
163
+ // }
164
+ fileName = clearString(fileName).slice(0, 100)
165
+
166
+ return fileName
167
+ }
168
+
169
+ export { createTest, testToFileName, enhanceMochaTest, serializeTest, deserializeTest, cloneTest }
170
+
171
+ export default {
172
+ createTest,
173
+ testToFileName,
174
+ enhanceMochaTest,
175
+ serializeTest,
176
+ deserializeTest,
177
+ cloneTest,
178
+ }
@@ -0,0 +1,42 @@
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
+ meta: Record<string, any>
11
+ notes: Array<{
12
+ type: string
13
+ text: string
14
+ }>
15
+ state: string
16
+ err?: Error
17
+ config: Record<string, any>
18
+ artifacts: string[]
19
+ inject: Record<string, any>
20
+ opts: Record<string, any>
21
+ throws?: Error | string | RegExp | Function
22
+ totalTimeout?: number
23
+ relativeFile?: string
24
+ addToSuite(suite: Mocha.Suite): void
25
+ applyOptions(opts: Record<string, any>): void
26
+ simplify(): Record<string, any>
27
+ toFileName(): string
28
+ addNote(type: string, note: string): void
29
+ codeceptjs: boolean
30
+ }
31
+
32
+ interface Suite extends MochaSuite {
33
+ title: string
34
+ tags: string[]
35
+ opts: Record<string, any>
36
+ totalTimeout?: number
37
+ addTest(test: Test): void
38
+ applyOptions(opts: Record<string, any>): void
39
+ codeceptjs: boolean
40
+ }
41
+ }
42
+ }
@@ -0,0 +1,229 @@
1
+ import escapeRe from 'escape-string-regexp'
2
+ import { test, setup, teardown, suiteSetup, suiteTeardown, injected } from './asyncWrapper.js'
3
+ import ScenarioConfig from './scenarioConfig.js'
4
+ import FeatureConfig from './featureConfig.js'
5
+ import addDataContext from '../data/context.js'
6
+ import { createTest } from './test.js'
7
+ import { createSuite } from './suite.js'
8
+ import { HookConfig, AfterSuiteHook, AfterHook, BeforeSuiteHook, BeforeHook } from './hooks.js'
9
+ import { initMochaGlobals } from '../globals.js'
10
+ import common from 'mocha/lib/interfaces/common.js'
11
+ import container from '../container.js'
12
+
13
+ const setContextTranslation = context => {
14
+ // Try global container first, then local container instance
15
+ const containerToUse = global.container || container
16
+ if (!containerToUse) return
17
+
18
+ const translation = containerToUse.translation?.() || containerToUse.translation
19
+ const contexts = translation?.value?.('contexts')
20
+
21
+ if (contexts) {
22
+ for (const key of Object.keys(contexts)) {
23
+ if (context[key]) {
24
+ context[contexts[key]] = context[key]
25
+ }
26
+ }
27
+ }
28
+ }
29
+
30
+ /**
31
+ * Codecept-style interface:
32
+ *
33
+ * Feature('login');
34
+ *
35
+ * Scenario('login as regular user', ({I}) {
36
+ * I.fillField();
37
+ * I.click();
38
+ * I.see('Hello, '+data.login);
39
+ * });
40
+ *
41
+ * @param {Mocha.Suite} suite Root suite.
42
+ * @ignore
43
+ */
44
+ export default function (suite) {
45
+ const suites = [suite]
46
+ suite.timeout(0)
47
+ let afterAllHooks
48
+ let afterEachHooks
49
+ let afterAllHooksAreLoaded
50
+ let afterEachHooksAreLoaded
51
+
52
+ suite.on('pre-require', (context, file, mocha) => {
53
+ const cmn = common(suites, context, mocha)
54
+
55
+ const addScenario = function (title, opts = {}, fn) {
56
+ const suite = suites[0]
57
+
58
+ if (typeof opts === 'function' && !fn) {
59
+ fn = opts
60
+ opts = {}
61
+ }
62
+ if (suite.pending) {
63
+ fn = null
64
+ }
65
+ const test = createTest(title, fn)
66
+ test.file = file
67
+ test.addToSuite(suite)
68
+ test.applyOptions(opts)
69
+
70
+ return new ScenarioConfig(test)
71
+ }
72
+
73
+ // create dispatcher
74
+
75
+ context.BeforeAll = cmn.before
76
+ context.AfterAll = cmn.after
77
+
78
+ context.run = mocha.options.delay && common.runWithSuite(suite)
79
+ /**
80
+ * Describe a "suite" with the given `title`
81
+ * and callback `fn` containing nested suites
82
+ * and/or tests.
83
+ * @global
84
+ * @param {string} title
85
+ * @param {Object<string, *>} [opts]
86
+ * @returns {FeatureConfig}
87
+ */
88
+
89
+ context.Feature = function (title, opts) {
90
+ if (suites.length > 1) {
91
+ suites.shift()
92
+ }
93
+
94
+ afterAllHooks = []
95
+ afterEachHooks = []
96
+ afterAllHooksAreLoaded = false
97
+ afterEachHooksAreLoaded = false
98
+
99
+ const suite = createSuite(suites[0], title)
100
+ suite.applyOptions(opts)
101
+
102
+ suite.file = file
103
+ suites.unshift(suite)
104
+ suite.beforeEach('codeceptjs.before', setup(suite))
105
+ afterEachHooks.push(['finalize codeceptjs', teardown(suite)])
106
+
107
+ suite.beforeAll('codeceptjs.beforeSuite', suiteSetup(suite))
108
+ afterAllHooks.push(['codeceptjs.afterSuite', suiteTeardown(suite)])
109
+
110
+ return new FeatureConfig(suite)
111
+ }
112
+
113
+ /**
114
+ * Pending test suite.
115
+ * @global
116
+ * @kind constant
117
+ * @type {CodeceptJS.IFeature}
118
+ */
119
+ context.xFeature = context.Feature.skip = function (title, opts) {
120
+ const skipInfo = {
121
+ skipped: true,
122
+ message: 'Skipped due to "skip" on Feature.',
123
+ }
124
+ return context.Feature(title, { ...opts, skipInfo })
125
+ }
126
+
127
+ context.BeforeSuite = function (fn) {
128
+ suites[0].beforeAll('BeforeSuite', injected(fn, suites[0], 'beforeSuite'))
129
+ return new HookConfig(new BeforeSuiteHook({ suite: suites[0] }))
130
+ }
131
+
132
+ context.AfterSuite = function (fn) {
133
+ afterAllHooks.unshift(['AfterSuite', injected(fn, suites[0], 'afterSuite')])
134
+ return new HookConfig(new AfterSuiteHook({ suite: suites[0] }))
135
+ }
136
+
137
+ context.Background = context.Before = function (fn) {
138
+ suites[0].beforeEach('Before', injected(fn, suites[0], 'before'))
139
+ return new HookConfig(new BeforeHook({ suite: suites[0] }))
140
+ }
141
+
142
+ context.After = function (fn) {
143
+ afterEachHooks.unshift(['After', injected(fn, suites[0], 'after')])
144
+ return new HookConfig(new AfterHook({ suite: suites[0] }))
145
+ }
146
+
147
+ /**
148
+ * Describe a specification or test-case
149
+ * with the given `title` and callback `fn`
150
+ * acting as a thunk.
151
+ * @ignore
152
+ */
153
+ context.Scenario = addScenario
154
+ /**
155
+ * Exclusive test-case.
156
+ * @ignore
157
+ */
158
+ context.Scenario.only = function (title, opts, fn) {
159
+ const reString = `^${escapeRe(`${suites[0].title}: ${title}`.replace(/( \| {.+})?$/g, ''))}`
160
+ mocha.grep(new RegExp(reString))
161
+ process.env.SCENARIO_ONLY = true
162
+ return addScenario(title, opts, fn)
163
+ }
164
+
165
+ /**
166
+ * Pending test case.
167
+ * @global
168
+ * @kind constant
169
+ * @type {CodeceptJS.IScenario}
170
+ */
171
+ context.xScenario = context.Scenario.skip = function (title, opts = {}, fn) {
172
+ if (typeof opts === 'function' && !fn) {
173
+ opts = {}
174
+ }
175
+
176
+ return context.Scenario(title, opts)
177
+ }
178
+
179
+ /**
180
+ * Pending test case with message: 'Test not implemented!'.
181
+ * @global
182
+ * @kind constant
183
+ * @type {CodeceptJS.IScenario}
184
+ */
185
+ context.Scenario.todo = function (title, opts = {}, fn) {
186
+ if (typeof opts === 'function' && !fn) {
187
+ fn = opts
188
+ opts = {}
189
+ }
190
+
191
+ const skipInfo = {
192
+ message: 'Test not implemented!',
193
+ description: fn ? fn.toString() : '',
194
+ }
195
+
196
+ return context.Scenario(title, { ...opts, skipInfo })
197
+ }
198
+
199
+ /**
200
+ * For translation
201
+ */
202
+
203
+ setContextTranslation(context)
204
+
205
+ // Initialize all globals
206
+ initMochaGlobals(context)
207
+
208
+ addDataContext(context)
209
+ })
210
+
211
+ suite.on('post-require', () => {
212
+ /**
213
+ * load hooks from arrays to suite to prevent reordering
214
+ */
215
+ if (!afterEachHooksAreLoaded && Array.isArray(afterEachHooks)) {
216
+ afterEachHooks.forEach(hook => {
217
+ suites[0].afterEach(hook[0], hook[1])
218
+ })
219
+ afterEachHooksAreLoaded = true
220
+ }
221
+
222
+ if (!afterAllHooksAreLoaded && Array.isArray(afterAllHooks)) {
223
+ afterAllHooks.forEach(hook => {
224
+ suites[0].afterAll(hook[0], hook[1])
225
+ })
226
+ afterAllHooksAreLoaded = true
227
+ }
228
+ })
229
+ }