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
package/lib/els.js ADDED
@@ -0,0 +1,160 @@
1
+ import output from './output.js'
2
+ import store from './store.js'
3
+ import container from './container.js'
4
+ import StepConfig from './step/config.js'
5
+ import recordStep from './step/record.js'
6
+ import FuncStep from './step/func.js'
7
+ import { truth } from './assert/truth.js'
8
+ import { isAsyncFunction, humanizeFunction } from './utils.js'
9
+
10
+ function element(purpose, locator, fn) {
11
+ let stepConfig
12
+ if (arguments[arguments.length - 1] instanceof StepConfig) {
13
+ stepConfig = arguments[arguments.length - 1]
14
+ }
15
+
16
+ if (!fn || fn === stepConfig) {
17
+ fn = locator
18
+ locator = purpose
19
+ purpose = 'first element'
20
+ }
21
+
22
+ const step = prepareStep(purpose, locator, fn)
23
+ if (!step) return
24
+
25
+ return executeStep(
26
+ step,
27
+ async () => {
28
+ const els = await step.helper._locate(locator)
29
+ output.debug(`Found ${els.length} elements, using first element`)
30
+
31
+ return fn(els[0])
32
+ },
33
+ stepConfig,
34
+ )
35
+ }
36
+
37
+ function eachElement(purpose, locator, fn) {
38
+ if (!fn) {
39
+ fn = locator
40
+ locator = purpose
41
+ purpose = 'for each element'
42
+ }
43
+
44
+ const step = prepareStep(purpose, locator, fn)
45
+ if (!step) return
46
+
47
+ return executeStep(step, async () => {
48
+ const els = await step.helper._locate(locator)
49
+ output.debug(`Found ${els.length} elements for each elements to iterate`)
50
+
51
+ const errs = []
52
+ let i = 0
53
+ for (const el of els) {
54
+ try {
55
+ await fn(el, i)
56
+ } catch (err) {
57
+ output.error(`eachElement: failed operation on element #${i} ${el}`)
58
+ errs.push(err)
59
+ }
60
+ i++
61
+ }
62
+
63
+ if (errs.length) {
64
+ throw errs[0]
65
+ }
66
+ })
67
+ }
68
+
69
+ function expectElement(locator, fn) {
70
+ const step = prepareStep('expect element to be', locator, fn)
71
+ if (!step) return
72
+
73
+ return executeStep(step, async () => {
74
+ const els = await step.helper._locate(locator)
75
+ output.debug(`Found ${els.length} elements, first will be used for assertion`)
76
+
77
+ const result = await fn(els[0])
78
+ const assertion = truth(`element (${locator})`, fn.toString())
79
+ assertion.assert(result)
80
+ })
81
+ }
82
+
83
+ function expectAnyElement(locator, fn) {
84
+ const step = prepareStep('expect any element to be', locator, fn)
85
+ if (!step) return
86
+
87
+ return executeStep(step, async () => {
88
+ const els = await step.helper._locate(locator)
89
+ output.debug(`Found ${els.length} elements, at least one should pass the assertion`)
90
+
91
+ const assertion = truth(`any element of (${locator})`, fn.toString())
92
+
93
+ let found = false
94
+ for (const el of els) {
95
+ const result = await fn(el)
96
+ if (result) {
97
+ found = true
98
+ break
99
+ }
100
+ }
101
+ if (!found) throw assertion.getException()
102
+ })
103
+ }
104
+
105
+ function expectAllElements(locator, fn) {
106
+ const step = prepareStep('expect all elements', locator, fn)
107
+ if (!step) return
108
+
109
+ return executeStep(step, async () => {
110
+ const els = await step.helper._locate(locator)
111
+ output.debug(`Found ${els.length} elements, all should pass the assertion`)
112
+
113
+ let i = 1
114
+ for (const el of els) {
115
+ output.debug(`checking element #${i}: ${el}`)
116
+ const result = await fn(el)
117
+ const assertion = truth(`element #${i} of (${locator})`, humanizeFunction(fn))
118
+ assertion.assert(result)
119
+ i++
120
+ }
121
+ })
122
+ }
123
+
124
+ export { element, eachElement, expectElement, expectAnyElement, expectAllElements }
125
+
126
+ export default {
127
+ element,
128
+ eachElement,
129
+ expectElement,
130
+ expectAnyElement,
131
+ expectAllElements,
132
+ }
133
+
134
+ function prepareStep(purpose, locator, fn) {
135
+ if (store.dryRun) return
136
+ const helpers = Object.values(container.helpers())
137
+
138
+ const helper = helpers.filter(h => !!h._locate)[0]
139
+
140
+ if (!helper) {
141
+ throw new Error('No helper enabled with _locate method with returns a list of elements.')
142
+ }
143
+
144
+ if (!isAsyncFunction(fn)) {
145
+ throw new Error('Async function should be passed into each element')
146
+ }
147
+
148
+ const isAssertion = purpose.startsWith('expect')
149
+
150
+ const step = new FuncStep(`${purpose} within "${locator}" ${isAssertion ? 'to be' : 'to'}`)
151
+ step.setHelper(helper)
152
+ step.setArguments([humanizeFunction(fn)]) // user defined function is a passed argument
153
+
154
+ return step
155
+ }
156
+
157
+ async function executeStep(step, action, stepConfig = {}) {
158
+ step.setCallable(action)
159
+ return recordStep(step, [stepConfig])
160
+ }
package/lib/event.js CHANGED
@@ -1,15 +1,16 @@
1
- const debug = require('debug')('codeceptjs:event');
2
- const events = require('events');
3
- const { error } = require('./output');
1
+ import debugModule from 'debug'
2
+ const debug = debugModule('codeceptjs:event')
3
+ import events from 'events'
4
+ import output from './output.js'
4
5
 
5
- const dispatcher = new events.EventEmitter();
6
+ const dispatcher = new events.EventEmitter()
6
7
 
7
- dispatcher.setMaxListeners(50);
8
+ dispatcher.setMaxListeners(50)
8
9
  /**
9
10
  * @namespace
10
11
  * @alias event
11
12
  */
12
- module.exports = {
13
+ export default {
13
14
  /**
14
15
  * @type {NodeJS.EventEmitter}
15
16
  * @constant
@@ -54,12 +55,16 @@ module.exports = {
54
55
  * @inner
55
56
  * @property {'hook.start'} started
56
57
  * @property {'hook.passed'} passed
58
+ * @property {'hook.failed'} failed
59
+ * @property {'hook.finished'} finished
57
60
  */
58
61
  hook: {
59
62
  started: 'hook.start',
60
63
  passed: 'hook.passed',
61
64
  failed: 'hook.failed',
65
+ finished: 'hook.finished',
62
66
  },
67
+
63
68
  /**
64
69
  * @type {object}
65
70
  * @constant
@@ -140,33 +145,33 @@ module.exports = {
140
145
  * @param {*} [param]
141
146
  */
142
147
  emit(event, param) {
143
- let msg = `Emitted | ${event}`;
148
+ let msg = `Emitted | ${event}`
144
149
  if (param && param.toString()) {
145
- msg += ` (${param.toString()})`;
150
+ msg += ` (${param.toString()})`
146
151
  }
147
- debug(msg);
152
+ debug(msg)
148
153
  try {
149
- this.dispatcher.emit.apply(this.dispatcher, arguments);
154
+ this.dispatcher.emit.apply(this.dispatcher, arguments)
150
155
  } catch (err) {
151
- error(`Error processing ${event} event:`);
152
- error(err.stack);
156
+ output.error(`Error processing ${event} event:`)
157
+ output.error(err.stack)
153
158
  }
154
159
  },
155
160
 
156
161
  /** for testing only! */
157
- cleanDispatcher: () => {
158
- let event;
162
+ cleanDispatcher() {
163
+ let event
159
164
  for (event in this.test) {
160
- this.dispatcher.removeAllListeners(this.test[event]);
165
+ this.dispatcher.removeAllListeners(this.test[event])
161
166
  }
162
167
  for (event in this.suite) {
163
- this.dispatcher.removeAllListeners(this.test[event]);
168
+ this.dispatcher.removeAllListeners(this.suite[event])
164
169
  }
165
170
  for (event in this.step) {
166
- this.dispatcher.removeAllListeners(this.test[event]);
171
+ this.dispatcher.removeAllListeners(this.step[event])
167
172
  }
168
173
  for (event in this.all) {
169
- this.dispatcher.removeAllListeners(this.test[event]);
174
+ this.dispatcher.removeAllListeners(this.all[event])
170
175
  }
171
176
  },
172
- };
177
+ }
package/lib/globals.js ADDED
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Global variables initialization module
3
+ *
4
+ * Centralizes all global variable setup for CodeceptJS from codecept.js and mocha/ui.js
5
+ */
6
+
7
+ import fsPath from 'path'
8
+ import ActorFactory from './actor.js'
9
+ import output from './output.js'
10
+ import locator from './locator.js'
11
+
12
+ /**
13
+ * Initialize CodeceptJS core globals
14
+ * Called from Codecept.initGlobals()
15
+ */
16
+ export async function initCodeceptGlobals(dir, config, container) {
17
+ global.codecept_dir = dir
18
+ global.output_dir = fsPath.resolve(dir, config.output)
19
+
20
+ if (config.noGlobals) return;
21
+ // Set up actor global - will use container when available
22
+ global.actor = global.codecept_actor = (obj) => {
23
+ return ActorFactory(obj, global.container || container)
24
+ }
25
+ global.Actor = global.actor
26
+
27
+ // Use dynamic imports for modules to avoid circular dependencies
28
+ global.pause = async (...args) => {
29
+ const pauseModule = await import('./pause.js')
30
+ return (pauseModule.default || pauseModule)(...args)
31
+ }
32
+
33
+ global.within = async (...args) => {
34
+ return (await import('./effects.js')).within(...args)
35
+ }
36
+
37
+ global.session = async (...args) => {
38
+ const sessionModule = await import('./session.js')
39
+ return (sessionModule.default || sessionModule)(...args)
40
+ }
41
+
42
+ const dataTableModule = await import('./data/table.js')
43
+ global.DataTable = dataTableModule.default || dataTableModule
44
+
45
+ global.locate = locatorQuery => {
46
+ return locator.build(locatorQuery)
47
+ }
48
+
49
+ global.inject = () => container.support()
50
+ global.share = container.share
51
+
52
+ const secretModule = await import('./secret.js')
53
+ global.secret = secretModule.secret || (secretModule.default && secretModule.default.secret)
54
+
55
+ global.codecept_debug = output.debug
56
+
57
+ const codeceptjsModule = await import('./index.js') // load all objects
58
+ global.codeceptjs = codeceptjsModule.default || codeceptjsModule
59
+
60
+ // BDD step definitions
61
+ const stepDefinitionsModule = await import('./mocha/bdd.js')
62
+ const stepDefinitions = stepDefinitionsModule.default || stepDefinitionsModule
63
+ global.Given = stepDefinitions.Given
64
+ global.When = stepDefinitions.When
65
+ global.Then = stepDefinitions.Then
66
+ global.DefineParameterType = stepDefinitions.defineParameterType
67
+
68
+ // debug mode
69
+ global.debugMode = false
70
+
71
+ // mask sensitive data
72
+ global.maskSensitiveData = config.maskSensitiveData || false
73
+
74
+ }
75
+
76
+ /**
77
+ * Initialize Mocha test framework globals (Feature, Scenario, etc.)
78
+ * Called from mocha/ui.js pre-require event
79
+ */
80
+ export function initMochaGlobals(context) {
81
+ // Mocha test framework globals
82
+ global.BeforeAll = context.BeforeAll
83
+ global.AfterAll = context.AfterAll
84
+ global.Feature = context.Feature
85
+ global.xFeature = context.xFeature
86
+ global.BeforeSuite = context.BeforeSuite
87
+ global.AfterSuite = context.AfterSuite
88
+ global.Background = context.Background
89
+ global.Before = context.Before
90
+ global.After = context.After
91
+ global.Scenario = context.Scenario
92
+ global.xScenario = context.xScenario
93
+ }
94
+
95
+ /**
96
+ * Clear all CodeceptJS globals (useful for testing/cleanup)
97
+ */
98
+ export function clearGlobals() {
99
+ getGlobalNames().forEach(name => delete global[name]);
100
+ }
101
+
102
+ /**
103
+ * Get list of all CodeceptJS global variable names
104
+ */
105
+ export function getGlobalNames() {
106
+ return [
107
+ 'codecept_dir',
108
+ 'output_dir',
109
+ 'actor',
110
+ 'codecept_actor',
111
+ 'Actor',
112
+ 'pause',
113
+ 'within',
114
+ 'session',
115
+ 'DataTable',
116
+ 'locate',
117
+ 'inject',
118
+ 'share',
119
+ 'secret',
120
+ 'codecept_debug',
121
+ 'codeceptjs',
122
+ 'Given',
123
+ 'When',
124
+ 'Then',
125
+ 'DefineParameterType',
126
+ 'debugMode',
127
+ 'maskSensitiveData',
128
+ 'BeforeAll',
129
+ 'AfterAll',
130
+ 'Feature',
131
+ 'xFeature',
132
+ 'BeforeSuite',
133
+ 'AfterSuite',
134
+ 'Background',
135
+ 'Before',
136
+ 'After',
137
+ 'Scenario',
138
+ 'xScenario',
139
+ 'container'
140
+ ]
141
+ }
package/lib/heal.js CHANGED
@@ -1,122 +1,125 @@
1
- const debug = require('debug')('codeceptjs:heal');
2
- const colors = require('chalk');
3
- const Container = require('./container');
4
- const recorder = require('./recorder');
5
- const output = require('./output');
6
- const event = require('./event');
1
+ import debugModule from 'debug'
2
+ const debug = debugModule('codeceptjs:heal')
3
+ import colors from 'chalk'
4
+ import recorder from './recorder.js'
5
+ import output from './output.js'
6
+ import event from './event.js'
7
7
 
8
8
  /**
9
9
  * @class
10
10
  */
11
11
  class Heal {
12
12
  constructor() {
13
- this.recipes = {};
14
- this.fixes = [];
15
- this.prepareFns = [];
16
- this.contextName = null;
17
- this.numHealed = 0;
13
+ this.recipes = {}
14
+ this.fixes = []
15
+ this.prepareFns = []
16
+ this.contextName = null
17
+ this.numHealed = 0
18
18
  }
19
19
 
20
20
  clear() {
21
- this.recipes = {};
22
- this.fixes = [];
23
- this.prepareFns = [];
24
- this.contextName = null;
25
- this.numHealed = 0;
21
+ this.recipes = {}
22
+ this.fixes = []
23
+ this.prepareFns = []
24
+ this.contextName = null
25
+ this.numHealed = 0
26
26
  }
27
27
 
28
28
  addRecipe(name, opts = {}) {
29
- if (!opts.priority) opts.priority = 0;
29
+ if (!opts.priority) opts.priority = 0
30
30
 
31
- if (!opts.fn) throw new Error(`Recipe ${name} should have a function 'fn' to execute`);
31
+ if (!opts.fn) throw new Error(`Recipe ${name} should have a function 'fn' to execute`)
32
32
 
33
- this.recipes[name] = opts;
33
+ this.recipes[name] = opts
34
34
  }
35
35
 
36
36
  connectToEvents() {
37
- event.dispatcher.on(event.suite.before, (suite) => {
38
- this.contextName = suite.title;
39
- });
37
+ event.dispatcher.on(event.suite.before, suite => {
38
+ this.contextName = suite.title
39
+ })
40
40
 
41
- event.dispatcher.on(event.test.started, (test) => {
42
- this.contextName = test.fullTitle();
43
- });
41
+ event.dispatcher.on(event.test.started, test => {
42
+ this.contextName = test.fullTitle()
43
+ })
44
44
 
45
45
  event.dispatcher.on(event.test.finished, () => {
46
- this.contextName = null;
47
- });
46
+ this.contextName = null
47
+ })
48
48
  }
49
49
 
50
50
  hasCorrespondingRecipes(step) {
51
- return matchRecipes(this.recipes, this.contextName)
52
- .filter(r => !r.steps || r.steps.includes(step.name))
53
- .length > 0;
51
+ return matchRecipes(this.recipes, this.contextName).filter(r => !r.steps || r.steps.includes(step.name)).length > 0
54
52
  }
55
53
 
56
54
  async getCodeSuggestions(context) {
57
- const suggestions = [];
58
- const recipes = matchRecipes(this.recipes, this.contextName);
55
+ const suggestions = []
56
+ const recipes = matchRecipes(this.recipes, this.contextName)
59
57
 
60
- debug('Recipes', recipes);
58
+ debug('Recipes', recipes)
61
59
 
62
- const currentOutputLevel = output.level();
63
- output.level(0);
60
+ const currentOutputLevel = output.level()
61
+ output.level(0)
64
62
 
65
- for (const [property, prepareFn] of Object.entries(recipes.map(r => r.prepare).filter(p => !!p).reduce((acc, obj) => ({ ...acc, ...obj }), {}))) {
66
- if (!prepareFn) continue;
63
+ for (const [property, prepareFn] of Object.entries(
64
+ recipes
65
+ .map(r => r.prepare)
66
+ .filter(p => !!p)
67
+ .reduce((acc, obj) => ({ ...acc, ...obj }), {}),
68
+ )) {
69
+ if (!prepareFn) continue
67
70
 
68
- if (context[property]) continue;
69
- context[property] = await prepareFn(Container.support());
71
+ if (context[property]) continue
72
+ context[property] = await prepareFn(global.inject())
70
73
  }
71
74
 
72
- output.level(currentOutputLevel);
75
+ output.level(currentOutputLevel)
73
76
 
74
77
  for (const recipe of recipes) {
75
- let snippets = await recipe.fn(context);
76
- if (!Array.isArray(snippets)) snippets = [snippets];
78
+ let snippets = await recipe.fn(context)
79
+ if (!Array.isArray(snippets)) snippets = [snippets]
77
80
 
78
81
  suggestions.push({
79
82
  name: recipe.name,
80
83
  snippets,
81
- });
84
+ })
82
85
  }
83
86
 
84
- return suggestions.filter(s => !isBlank(s.snippets));
87
+ return suggestions.filter(s => !isBlank(s.snippets))
85
88
  }
86
89
 
87
90
  async healStep(failedStep, error, failureContext = {}) {
88
- output.debug(`Trying to heal ${failedStep.toCode()} step`);
91
+ output.debug(`Trying to heal ${failedStep.toCode()} step`)
89
92
 
90
93
  Object.assign(failureContext, {
91
94
  error,
92
95
  step: failedStep,
93
96
  prevSteps: failureContext?.test?.steps?.slice(0, -1) || [],
94
- });
97
+ })
95
98
 
96
- const suggestions = await this.getCodeSuggestions(failureContext);
99
+ const suggestions = await this.getCodeSuggestions(failureContext)
97
100
 
98
101
  if (suggestions.length === 0) {
99
- debug('No healing suggestions found');
100
- throw error;
102
+ debug('No healing suggestions found')
103
+ throw error
101
104
  }
102
105
 
103
- output.debug(`Received ${suggestions.length} suggestion${suggestions.length === 1 ? '' : 's'}`);
106
+ output.debug(`Received ${suggestions.length} suggestion${suggestions.length === 1 ? '' : 's'}`)
104
107
 
105
- debug(suggestions);
108
+ debug(suggestions)
106
109
 
107
110
  for (const suggestion of suggestions) {
108
111
  for (const codeSnippet of suggestion.snippets) {
109
112
  try {
110
- debug('Executing', codeSnippet);
111
- recorder.catch((e) => {
112
- debug(e);
113
- });
113
+ debug('Executing', codeSnippet)
114
+ recorder.catch(e => {
115
+ debug(e)
116
+ })
114
117
 
115
118
  if (typeof codeSnippet === 'string') {
116
- const I = Container.support('I');
117
- await eval(codeSnippet); // eslint-disable-line
119
+ const I = global.container.support('I')
120
+ await eval(codeSnippet)
118
121
  } else if (typeof codeSnippet === 'function') {
119
- await codeSnippet(Container.support());
122
+ await codeSnippet(global.container.support())
120
123
  }
121
124
 
122
125
  this.fixes.push({
@@ -124,49 +127,54 @@ class Heal {
124
127
  test: failureContext?.test,
125
128
  step: failedStep,
126
129
  snippet: codeSnippet,
127
- });
130
+ })
131
+
132
+ if (failureContext?.test) {
133
+ const test = failureContext.test
134
+ let note = `This test was healed by '${suggestion.name}'`
135
+ note += `\n\nReplace the failed code:\n\n`
136
+ note += colors.red(`- ${failedStep.toCode()}\n`)
137
+ note += colors.green(`+ ${codeSnippet}\n`)
138
+ test.addNote('heal', note)
139
+ test.meta.healed = true
140
+ }
128
141
 
129
- recorder.add('healed', () => output.print(colors.bold.green(` Code healed successfully by ${suggestion.name}`), colors.gray('(no errors thrown)')));
130
- this.numHealed++;
142
+ recorder.add('healed', () => output.print(colors.bold.green(` Code healed successfully by ${suggestion.name}`), colors.gray('(no errors thrown)')))
143
+ this.numHealed++
131
144
  // recorder.session.restore();
132
- return;
145
+ return
133
146
  } catch (err) {
134
- debug('Failed to execute code', err);
135
- recorder.ignoreErr(err); // healing did not help
136
- recorder.catchWithoutStop(err);
137
- await recorder.promise(); // wait for all promises to resolve
147
+ debug('Failed to execute code', err)
148
+ recorder.ignoreErr(err) // healing did not help
149
+ recorder.catchWithoutStop(err)
150
+ await recorder.promise() // wait for all promises to resolve
138
151
  }
139
152
  }
140
153
  }
141
- output.debug(`Couldn't heal the code for ${failedStep.toCode()}`);
142
- recorder.throw(error);
154
+ output.debug(`Couldn't heal the code for ${failedStep.toCode()}`)
155
+ recorder.throw(error)
143
156
  }
144
157
 
145
- static setDefaultHealers() {
146
- require('./template/heal');
158
+ static async setDefaultHealers() {
159
+ await import('./template/heal.js')
147
160
  }
148
161
  }
149
162
 
150
- const heal = new Heal();
163
+ const heal = new Heal()
151
164
 
152
- module.exports = heal;
165
+ export default heal
153
166
 
154
167
  function matchRecipes(recipes, contextName) {
155
168
  return Object.entries(recipes)
156
169
  .filter(([, recipe]) => !contextName || !recipe.grep || new RegExp(recipe.grep).test(contextName))
157
170
  .sort(([, a], [, b]) => a.priority - b.priority)
158
171
  .map(([name, recipe]) => {
159
- recipe.name = name;
160
- return recipe;
172
+ recipe.name = name
173
+ return recipe
161
174
  })
162
- .filter(r => !!r.fn);
175
+ .filter(r => !!r.fn)
163
176
  }
164
177
 
165
178
  function isBlank(value) {
166
- return (
167
- value == null
168
- || (Array.isArray(value) && value.length === 0)
169
- || (typeof value === 'object' && Object.keys(value).length === 0)
170
- || (typeof value === 'string' && value.trim() === '')
171
- );
179
+ return value == null || (Array.isArray(value) && value.length === 0) || (typeof value === 'object' && Object.keys(value).length === 0) || (typeof value === 'string' && value.trim() === '')
172
180
  }
package/lib/helper/AI.js CHANGED
@@ -1,15 +1,16 @@
1
- const Helper = require('@codeceptjs/helper')
1
+ const HelperModule = require('@codeceptjs/helper')
2
2
  const ora = require('ora-classic')
3
3
  const fs = require('fs')
4
4
  const path = require('path')
5
5
  const ai = require('../ai')
6
- const standardActingHelpers = require('../plugin/standardActingHelpers')
7
6
  const Container = require('../container')
8
7
  const { splitByChunks, minifyHtml } = require('../html')
9
8
  const { beautify } = require('../utils')
10
9
  const output = require('../output')
11
10
  const { registerVariable } = require('../pause')
12
11
 
12
+ const standardActingHelpers = Container.STANDARD_ACTING_HELPERS
13
+
13
14
  const gtpRole = {
14
15
  user: 'user',
15
16
  }