codeceptjs 4.0.0-beta.2 → 4.0.0-beta.20

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 (209) hide show
  1. package/README.md +133 -120
  2. package/bin/codecept.js +107 -96
  3. package/bin/test-server.js +64 -0
  4. package/docs/webapi/clearCookie.mustache +1 -1
  5. package/docs/webapi/click.mustache +5 -1
  6. package/lib/actor.js +71 -103
  7. package/lib/ai.js +159 -188
  8. package/lib/assert/empty.js +22 -24
  9. package/lib/assert/equal.js +30 -37
  10. package/lib/assert/error.js +14 -14
  11. package/lib/assert/include.js +43 -48
  12. package/lib/assert/throws.js +11 -11
  13. package/lib/assert/truth.js +22 -22
  14. package/lib/assert.js +20 -18
  15. package/lib/codecept.js +262 -162
  16. package/lib/colorUtils.js +50 -52
  17. package/lib/command/check.js +206 -0
  18. package/lib/command/configMigrate.js +56 -51
  19. package/lib/command/definitions.js +96 -109
  20. package/lib/command/dryRun.js +77 -79
  21. package/lib/command/generate.js +234 -194
  22. package/lib/command/gherkin/init.js +42 -33
  23. package/lib/command/gherkin/snippets.js +76 -74
  24. package/lib/command/gherkin/steps.js +20 -17
  25. package/lib/command/info.js +74 -38
  26. package/lib/command/init.js +301 -290
  27. package/lib/command/interactive.js +41 -32
  28. package/lib/command/list.js +28 -27
  29. package/lib/command/run-multiple/chunk.js +51 -48
  30. package/lib/command/run-multiple/collection.js +5 -5
  31. package/lib/command/run-multiple/run.js +5 -1
  32. package/lib/command/run-multiple.js +97 -97
  33. package/lib/command/run-rerun.js +19 -25
  34. package/lib/command/run-workers.js +68 -92
  35. package/lib/command/run.js +39 -27
  36. package/lib/command/utils.js +80 -64
  37. package/lib/command/workers/runTests.js +388 -226
  38. package/lib/config.js +109 -50
  39. package/lib/container.js +641 -261
  40. package/lib/data/context.js +60 -61
  41. package/lib/data/dataScenarioConfig.js +47 -47
  42. package/lib/data/dataTableArgument.js +32 -32
  43. package/lib/data/table.js +22 -22
  44. package/lib/effects.js +307 -0
  45. package/lib/element/WebElement.js +327 -0
  46. package/lib/els.js +160 -0
  47. package/lib/event.js +173 -163
  48. package/lib/globals.js +141 -0
  49. package/lib/heal.js +89 -85
  50. package/lib/helper/AI.js +131 -41
  51. package/lib/helper/ApiDataFactory.js +107 -75
  52. package/lib/helper/Appium.js +542 -404
  53. package/lib/helper/FileSystem.js +100 -79
  54. package/lib/helper/GraphQL.js +44 -43
  55. package/lib/helper/GraphQLDataFactory.js +52 -52
  56. package/lib/helper/JSONResponse.js +126 -88
  57. package/lib/helper/Mochawesome.js +54 -29
  58. package/lib/helper/Playwright.js +2547 -1316
  59. package/lib/helper/Puppeteer.js +1578 -1181
  60. package/lib/helper/REST.js +209 -68
  61. package/lib/helper/WebDriver.js +1482 -1342
  62. package/lib/helper/errors/ConnectionRefused.js +6 -6
  63. package/lib/helper/errors/ElementAssertion.js +11 -16
  64. package/lib/helper/errors/ElementNotFound.js +5 -9
  65. package/lib/helper/errors/RemoteBrowserConnectionRefused.js +5 -5
  66. package/lib/helper/extras/Console.js +11 -11
  67. package/lib/helper/extras/PlaywrightLocator.js +110 -0
  68. package/lib/helper/extras/PlaywrightPropEngine.js +18 -18
  69. package/lib/helper/extras/PlaywrightReactVueLocator.js +17 -8
  70. package/lib/helper/extras/PlaywrightRestartOpts.js +25 -11
  71. package/lib/helper/extras/Popup.js +22 -22
  72. package/lib/helper/extras/React.js +27 -28
  73. package/lib/helper/network/actions.js +36 -42
  74. package/lib/helper/network/utils.js +78 -84
  75. package/lib/helper/scripts/blurElement.js +5 -5
  76. package/lib/helper/scripts/focusElement.js +5 -5
  77. package/lib/helper/scripts/highlightElement.js +8 -8
  78. package/lib/helper/scripts/isElementClickable.js +34 -34
  79. package/lib/helper.js +2 -3
  80. package/lib/history.js +23 -19
  81. package/lib/hooks.js +8 -8
  82. package/lib/html.js +94 -104
  83. package/lib/index.js +38 -27
  84. package/lib/listener/config.js +30 -23
  85. package/lib/listener/emptyRun.js +54 -0
  86. package/lib/listener/enhancedGlobalRetry.js +110 -0
  87. package/lib/listener/exit.js +16 -18
  88. package/lib/listener/globalRetry.js +70 -0
  89. package/lib/listener/globalTimeout.js +181 -0
  90. package/lib/listener/helpers.js +76 -51
  91. package/lib/listener/mocha.js +10 -11
  92. package/lib/listener/result.js +11 -0
  93. package/lib/listener/retryEnhancer.js +85 -0
  94. package/lib/listener/steps.js +71 -59
  95. package/lib/listener/store.js +20 -0
  96. package/lib/locator.js +214 -197
  97. package/lib/mocha/asyncWrapper.js +274 -0
  98. package/lib/mocha/bdd.js +167 -0
  99. package/lib/mocha/cli.js +341 -0
  100. package/lib/mocha/factory.js +163 -0
  101. package/lib/mocha/featureConfig.js +89 -0
  102. package/lib/mocha/gherkin.js +231 -0
  103. package/lib/mocha/hooks.js +121 -0
  104. package/lib/mocha/index.js +21 -0
  105. package/lib/mocha/inject.js +46 -0
  106. package/lib/{interfaces → mocha}/scenarioConfig.js +58 -34
  107. package/lib/mocha/suite.js +89 -0
  108. package/lib/mocha/test.js +184 -0
  109. package/lib/mocha/types.d.ts +42 -0
  110. package/lib/mocha/ui.js +242 -0
  111. package/lib/output.js +141 -71
  112. package/lib/parser.js +47 -44
  113. package/lib/pause.js +173 -145
  114. package/lib/plugin/analyze.js +403 -0
  115. package/lib/plugin/{autoLogin.js → auth.js} +178 -79
  116. package/lib/plugin/autoDelay.js +36 -40
  117. package/lib/plugin/coverage.js +131 -78
  118. package/lib/plugin/customLocator.js +22 -21
  119. package/lib/plugin/customReporter.js +53 -0
  120. package/lib/plugin/enhancedRetryFailedStep.js +99 -0
  121. package/lib/plugin/heal.js +101 -110
  122. package/lib/plugin/htmlReporter.js +3648 -0
  123. package/lib/plugin/pageInfo.js +140 -0
  124. package/lib/plugin/pauseOnFail.js +12 -11
  125. package/lib/plugin/retryFailedStep.js +82 -47
  126. package/lib/plugin/screenshotOnFail.js +111 -92
  127. package/lib/plugin/stepByStepReport.js +159 -101
  128. package/lib/plugin/stepTimeout.js +20 -25
  129. package/lib/plugin/subtitles.js +38 -38
  130. package/lib/recorder.js +193 -130
  131. package/lib/rerun.js +94 -49
  132. package/lib/result.js +238 -0
  133. package/lib/retryCoordinator.js +207 -0
  134. package/lib/secret.js +20 -18
  135. package/lib/session.js +95 -89
  136. package/lib/step/base.js +239 -0
  137. package/lib/step/comment.js +10 -0
  138. package/lib/step/config.js +50 -0
  139. package/lib/step/func.js +46 -0
  140. package/lib/step/helper.js +50 -0
  141. package/lib/step/meta.js +99 -0
  142. package/lib/step/record.js +74 -0
  143. package/lib/step/retry.js +11 -0
  144. package/lib/step/section.js +55 -0
  145. package/lib/step.js +18 -329
  146. package/lib/steps.js +54 -0
  147. package/lib/store.js +38 -7
  148. package/lib/template/heal.js +3 -12
  149. package/lib/template/prompts/generatePageObject.js +31 -0
  150. package/lib/template/prompts/healStep.js +13 -0
  151. package/lib/template/prompts/writeStep.js +9 -0
  152. package/lib/test-server.js +334 -0
  153. package/lib/timeout.js +60 -0
  154. package/lib/transform.js +8 -8
  155. package/lib/translation.js +34 -21
  156. package/lib/utils/loaderCheck.js +124 -0
  157. package/lib/utils/mask_data.js +47 -0
  158. package/lib/utils/typescript.js +237 -0
  159. package/lib/utils.js +411 -228
  160. package/lib/workerStorage.js +37 -34
  161. package/lib/workers.js +532 -296
  162. package/package.json +124 -95
  163. package/translations/de-DE.js +5 -3
  164. package/translations/fr-FR.js +5 -4
  165. package/translations/index.js +22 -12
  166. package/translations/it-IT.js +4 -3
  167. package/translations/ja-JP.js +4 -3
  168. package/translations/nl-NL.js +76 -0
  169. package/translations/pl-PL.js +4 -3
  170. package/translations/pt-BR.js +4 -3
  171. package/translations/ru-RU.js +4 -3
  172. package/translations/utils.js +10 -0
  173. package/translations/zh-CN.js +4 -3
  174. package/translations/zh-TW.js +4 -3
  175. package/typings/index.d.ts +546 -185
  176. package/typings/promiseBasedTypes.d.ts +150 -875
  177. package/typings/types.d.ts +547 -992
  178. package/lib/cli.js +0 -249
  179. package/lib/dirname.js +0 -5
  180. package/lib/helper/Expect.js +0 -425
  181. package/lib/helper/ExpectHelper.js +0 -399
  182. package/lib/helper/MockServer.js +0 -223
  183. package/lib/helper/Nightmare.js +0 -1411
  184. package/lib/helper/Protractor.js +0 -1835
  185. package/lib/helper/SoftExpectHelper.js +0 -381
  186. package/lib/helper/TestCafe.js +0 -1410
  187. package/lib/helper/clientscripts/nightmare.js +0 -213
  188. package/lib/helper/testcafe/testControllerHolder.js +0 -42
  189. package/lib/helper/testcafe/testcafe-utils.js +0 -63
  190. package/lib/interfaces/bdd.js +0 -98
  191. package/lib/interfaces/featureConfig.js +0 -69
  192. package/lib/interfaces/gherkin.js +0 -195
  193. package/lib/listener/artifacts.js +0 -19
  194. package/lib/listener/retry.js +0 -68
  195. package/lib/listener/timeout.js +0 -109
  196. package/lib/mochaFactory.js +0 -110
  197. package/lib/plugin/allure.js +0 -15
  198. package/lib/plugin/commentStep.js +0 -136
  199. package/lib/plugin/debugErrors.js +0 -67
  200. package/lib/plugin/eachElement.js +0 -127
  201. package/lib/plugin/fakerTransform.js +0 -49
  202. package/lib/plugin/retryTo.js +0 -121
  203. package/lib/plugin/selenoid.js +0 -371
  204. package/lib/plugin/standardActingHelpers.js +0 -9
  205. package/lib/plugin/tryTo.js +0 -105
  206. package/lib/plugin/wdio.js +0 -246
  207. package/lib/scenario.js +0 -222
  208. package/lib/ui.js +0 -238
  209. package/lib/within.js +0 -70
@@ -0,0 +1,184 @@
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
+
82
+ // Restore the custom fullTitle function to maintain consistency with original test
83
+ if (test.parent) {
84
+ test.fullTitle = () => `${test.parent.title}: ${test.title}`
85
+ }
86
+
87
+ return test
88
+ }
89
+
90
+ function serializeTest(test, error = null) {
91
+ // test = { ...test }
92
+
93
+ if (test.start && !test.duration) {
94
+ const end = +new Date()
95
+ test.duration = end - test.start
96
+ }
97
+
98
+ let err
99
+
100
+ if (test.err) {
101
+ err = serializeError(test.err)
102
+ test.state = 'failed'
103
+ } else if (error) {
104
+ err = serializeError(error)
105
+ test.state = 'failed'
106
+ }
107
+ const parent = {}
108
+ if (test.parent) {
109
+ parent.title = test.parent.title
110
+ }
111
+
112
+ if (test.opts) {
113
+ Object.keys(test.opts).forEach(k => {
114
+ if (typeof test.opts[k] === 'object') delete test.opts[k]
115
+ if (typeof test.opts[k] === 'function') delete test.opts[k]
116
+ })
117
+ }
118
+
119
+ let steps = undefined
120
+ if (Array.isArray(test.steps)) {
121
+ steps = test.steps.map(step => (step.simplify ? step.simplify() : step))
122
+ }
123
+
124
+ return {
125
+ opts: test.opts || {},
126
+ tags: test.tags || [],
127
+ uid: test.uid,
128
+ retries: test._retries,
129
+ title: test.title,
130
+ state: test.state,
131
+ notes: test.notes || [],
132
+ meta: test.meta || {},
133
+ artifacts: test.artifacts || {},
134
+ duration: test.duration || 0,
135
+ err,
136
+ parent,
137
+ steps,
138
+ }
139
+ }
140
+
141
+ function cloneTest(test) {
142
+ return deserializeTest(serializeTest(test))
143
+ }
144
+
145
+ /**
146
+ * Get a filename from the test object
147
+ * @param {CodeceptJS.Test} test
148
+ * @param {Object} options
149
+ * @param {string} options.suffix Add a suffix to the filename
150
+ * @param {boolean} options.unique Add a unique suffix to the file
151
+ *
152
+ * @returns {string} the filename
153
+ */
154
+ function testToFileName(test, { suffix = '', unique = false } = {}) {
155
+ let fileName = test.title
156
+
157
+ if (unique) fileName = `${fileName}_${test?.uid || Math.floor(new Date().getTime() / 1000)}`
158
+ if (suffix) fileName = `${fileName}_${suffix}`
159
+ // remove tags with empty string (disable for now)
160
+ // fileName = fileName.replace(/\@\w+/g, '')
161
+ fileName = fileName.slice(0, 100)
162
+ if (fileName.indexOf('{') !== -1) {
163
+ fileName = fileName.substr(0, fileName.indexOf('{') - 3).trim()
164
+ }
165
+ if (test.ctx && test.ctx.test && test.ctx.test.type === 'hook') fileName = clearString(`${test.title}_${test.ctx.test.title}`)
166
+ // TODO: add suite title to file name
167
+ // if (test.parent && test.parent.title) {
168
+ // fileName = `${clearString(test.parent.title)}_${fileName}`
169
+ // }
170
+ fileName = clearString(fileName).slice(0, 100)
171
+
172
+ return fileName
173
+ }
174
+
175
+ export { createTest, testToFileName, enhanceMochaTest, serializeTest, deserializeTest, cloneTest }
176
+
177
+ export default {
178
+ createTest,
179
+ testToFileName,
180
+ enhanceMochaTest,
181
+ serializeTest,
182
+ deserializeTest,
183
+ cloneTest,
184
+ }
@@ -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,242 @@
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
+ * Exclusive test suite - runs only this feature.
115
+ * @global
116
+ * @kind constant
117
+ * @type {CodeceptJS.IFeature}
118
+ */
119
+ context.Feature.only = function (title, opts) {
120
+ const reString = `^${escapeRe(`${title}:`)}`
121
+ mocha.grep(new RegExp(reString))
122
+ process.env.FEATURE_ONLY = true
123
+ return context.Feature(title, opts)
124
+ }
125
+
126
+ /**
127
+ * Pending test suite.
128
+ * @global
129
+ * @kind constant
130
+ * @type {CodeceptJS.IFeature}
131
+ */
132
+ context.xFeature = context.Feature.skip = function (title, opts) {
133
+ const skipInfo = {
134
+ skipped: true,
135
+ message: 'Skipped due to "skip" on Feature.',
136
+ }
137
+ return context.Feature(title, { ...opts, skipInfo })
138
+ }
139
+
140
+ context.BeforeSuite = function (fn) {
141
+ suites[0].beforeAll('BeforeSuite', injected(fn, suites[0], 'beforeSuite'))
142
+ return new HookConfig(new BeforeSuiteHook({ suite: suites[0] }))
143
+ }
144
+
145
+ context.AfterSuite = function (fn) {
146
+ afterAllHooks.unshift(['AfterSuite', injected(fn, suites[0], 'afterSuite')])
147
+ return new HookConfig(new AfterSuiteHook({ suite: suites[0] }))
148
+ }
149
+
150
+ context.Background = context.Before = function (fn) {
151
+ suites[0].beforeEach('Before', injected(fn, suites[0], 'before'))
152
+ return new HookConfig(new BeforeHook({ suite: suites[0] }))
153
+ }
154
+
155
+ context.After = function (fn) {
156
+ afterEachHooks.unshift(['After', injected(fn, suites[0], 'after')])
157
+ return new HookConfig(new AfterHook({ suite: suites[0] }))
158
+ }
159
+
160
+ /**
161
+ * Describe a specification or test-case
162
+ * with the given `title` and callback `fn`
163
+ * acting as a thunk.
164
+ * @ignore
165
+ */
166
+ context.Scenario = addScenario
167
+ /**
168
+ * Exclusive test-case.
169
+ * @ignore
170
+ */
171
+ context.Scenario.only = function (title, opts, fn) {
172
+ const reString = `^${escapeRe(`${suites[0].title}: ${title}`.replace(/( \| {.+})?$/g, ''))}`
173
+ mocha.grep(new RegExp(reString))
174
+ process.env.SCENARIO_ONLY = true
175
+ return addScenario(title, opts, fn)
176
+ }
177
+
178
+ /**
179
+ * Pending test case.
180
+ * @global
181
+ * @kind constant
182
+ * @type {CodeceptJS.IScenario}
183
+ */
184
+ context.xScenario = context.Scenario.skip = function (title, opts = {}, fn) {
185
+ if (typeof opts === 'function' && !fn) {
186
+ opts = {}
187
+ }
188
+
189
+ return context.Scenario(title, opts)
190
+ }
191
+
192
+ /**
193
+ * Pending test case with message: 'Test not implemented!'.
194
+ * @global
195
+ * @kind constant
196
+ * @type {CodeceptJS.IScenario}
197
+ */
198
+ context.Scenario.todo = function (title, opts = {}, fn) {
199
+ if (typeof opts === 'function' && !fn) {
200
+ fn = opts
201
+ opts = {}
202
+ }
203
+
204
+ const skipInfo = {
205
+ message: 'Test not implemented!',
206
+ description: fn ? fn.toString() : '',
207
+ }
208
+
209
+ return context.Scenario(title, { ...opts, skipInfo })
210
+ }
211
+
212
+ /**
213
+ * For translation
214
+ */
215
+
216
+ setContextTranslation(context)
217
+
218
+ // Initialize all globals
219
+ initMochaGlobals(context)
220
+
221
+ addDataContext(context)
222
+ })
223
+
224
+ suite.on('post-require', () => {
225
+ /**
226
+ * load hooks from arrays to suite to prevent reordering
227
+ */
228
+ if (!afterEachHooksAreLoaded && Array.isArray(afterEachHooks)) {
229
+ afterEachHooks.forEach(hook => {
230
+ suites[0].afterEach(hook[0], hook[1])
231
+ })
232
+ afterEachHooksAreLoaded = true
233
+ }
234
+
235
+ if (!afterAllHooksAreLoaded && Array.isArray(afterAllHooks)) {
236
+ afterAllHooks.forEach(hook => {
237
+ suites[0].afterAll(hook[0], hook[1])
238
+ })
239
+ afterAllHooksAreLoaded = true
240
+ }
241
+ })
242
+ }