codeceptjs 4.0.0-beta.7.esm-aria → 4.0.0-beta.9.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 (68) hide show
  1. package/README.md +46 -3
  2. package/bin/codecept.js +9 -0
  3. package/bin/test-server.js +64 -0
  4. package/docs/webapi/click.mustache +5 -1
  5. package/lib/ai.js +66 -102
  6. package/lib/codecept.js +99 -24
  7. package/lib/command/generate.js +33 -1
  8. package/lib/command/init.js +7 -3
  9. package/lib/command/run-workers.js +31 -2
  10. package/lib/command/run.js +15 -0
  11. package/lib/command/workers/runTests.js +331 -58
  12. package/lib/config.js +16 -5
  13. package/lib/container.js +15 -13
  14. package/lib/effects.js +1 -1
  15. package/lib/element/WebElement.js +327 -0
  16. package/lib/event.js +10 -1
  17. package/lib/helper/AI.js +11 -11
  18. package/lib/helper/ApiDataFactory.js +34 -6
  19. package/lib/helper/Appium.js +156 -42
  20. package/lib/helper/GraphQL.js +3 -3
  21. package/lib/helper/GraphQLDataFactory.js +4 -4
  22. package/lib/helper/JSONResponse.js +48 -40
  23. package/lib/helper/Mochawesome.js +24 -2
  24. package/lib/helper/Playwright.js +841 -153
  25. package/lib/helper/Puppeteer.js +263 -67
  26. package/lib/helper/REST.js +21 -0
  27. package/lib/helper/WebDriver.js +105 -16
  28. package/lib/helper/clientscripts/PollyWebDriverExt.js +1 -1
  29. package/lib/helper/extras/PlaywrightReactVueLocator.js +52 -0
  30. package/lib/helper/extras/PlaywrightRestartOpts.js +12 -1
  31. package/lib/helper/network/actions.js +8 -6
  32. package/lib/listener/config.js +11 -3
  33. package/lib/listener/enhancedGlobalRetry.js +110 -0
  34. package/lib/listener/globalTimeout.js +19 -4
  35. package/lib/listener/helpers.js +8 -2
  36. package/lib/listener/retryEnhancer.js +85 -0
  37. package/lib/listener/steps.js +12 -0
  38. package/lib/mocha/asyncWrapper.js +13 -3
  39. package/lib/mocha/cli.js +1 -1
  40. package/lib/mocha/factory.js +3 -0
  41. package/lib/mocha/gherkin.js +1 -1
  42. package/lib/mocha/test.js +6 -0
  43. package/lib/mocha/ui.js +13 -0
  44. package/lib/output.js +62 -18
  45. package/lib/plugin/coverage.js +16 -3
  46. package/lib/plugin/enhancedRetryFailedStep.js +99 -0
  47. package/lib/plugin/htmlReporter.js +3648 -0
  48. package/lib/plugin/retryFailedStep.js +1 -0
  49. package/lib/plugin/stepByStepReport.js +1 -1
  50. package/lib/recorder.js +28 -3
  51. package/lib/result.js +100 -23
  52. package/lib/retryCoordinator.js +207 -0
  53. package/lib/step/base.js +1 -1
  54. package/lib/step/comment.js +2 -2
  55. package/lib/step/meta.js +1 -1
  56. package/lib/template/heal.js +1 -1
  57. package/lib/template/prompts/generatePageObject.js +31 -0
  58. package/lib/template/prompts/healStep.js +13 -0
  59. package/lib/template/prompts/writeStep.js +9 -0
  60. package/lib/test-server.js +334 -0
  61. package/lib/utils/mask_data.js +47 -0
  62. package/lib/utils.js +87 -6
  63. package/lib/workerStorage.js +2 -1
  64. package/lib/workers.js +179 -23
  65. package/package.json +59 -47
  66. package/typings/index.d.ts +19 -7
  67. package/typings/promiseBasedTypes.d.ts +5534 -3764
  68. package/typings/types.d.ts +5789 -3775
@@ -121,6 +121,7 @@ export default function (config) {
121
121
  event.dispatcher.on(event.test.before, test => {
122
122
  // pass disableRetryFailedStep is a preferred way to disable retries
123
123
  // test.disableRetryFailedStep is used for backward compatibility
124
+ if (!test.opts) test.opts = {}
124
125
  if (test.opts.disableRetryFailedStep || test.disableRetryFailedStep) {
125
126
  store.autoRetries = false
126
127
  return // disable retry when a test is not active
@@ -2,7 +2,7 @@ import colors from 'chalk'
2
2
  import crypto from 'crypto'
3
3
  import figures from 'figures'
4
4
  import fs from 'fs'
5
- import mkdirp from 'mkdirp'
5
+ import { mkdirp } from 'mkdirp'
6
6
  import path from 'path'
7
7
  import cheerio from 'cheerio'
8
8
 
package/lib/recorder.js CHANGED
@@ -12,6 +12,7 @@ let running = false
12
12
  let errFn
13
13
  let queueId = 0
14
14
  let sessionId = null
15
+ let sessionStack = [] // Stack to support nested sessions
15
16
  let asyncErr = null
16
17
  let ignoredErrs = []
17
18
 
@@ -90,6 +91,7 @@ export default {
90
91
  if (promise && running) this.catch()
91
92
  queueId++
92
93
  sessionId = null
94
+ sessionStack = [] // Clear the session stack
93
95
  asyncErr = null
94
96
  output.log(`${currentQueue()} Starting recording promises`)
95
97
  promise = Promise.resolve()
@@ -124,8 +126,13 @@ export default {
124
126
  */
125
127
  start(name) {
126
128
  if (sessionId) {
127
- debug(`${currentQueue()}Session already started as ${sessionId}`)
128
- this.restore(sessionId)
129
+ debug(`${currentQueue()}Session already started as ${sessionId}, nesting session ${name}`)
130
+ // Push current session to stack instead of restoring it
131
+ sessionStack.push({
132
+ id: sessionId,
133
+ promise: promise,
134
+ running: this.running,
135
+ })
129
136
  }
130
137
  debug(`${currentQueue()}Starting <${name}> session`)
131
138
  tasks.push('--->')
@@ -143,9 +150,18 @@ export default {
143
150
  tasks.push('<---')
144
151
  debug(`${currentQueue()}Finalize <${name}> session`)
145
152
  this.running = false
146
- sessionId = null
147
153
  this.catch(errFn)
148
154
  promise = promise.then(() => oldPromises.pop())
155
+
156
+ // Restore parent session from stack if available
157
+ if (sessionStack.length > 0) {
158
+ const parentSession = sessionStack.pop()
159
+ sessionId = parentSession.id
160
+ this.running = parentSession.running
161
+ debug(`${currentQueue()}Restored parent session <${sessionId}>`)
162
+ } else {
163
+ sessionId = null
164
+ }
149
165
  },
150
166
 
151
167
  /**
@@ -398,6 +414,15 @@ export default {
398
414
  toString() {
399
415
  return `Queue: ${currentQueue()}\n\nTasks: ${this.scheduled()}`
400
416
  },
417
+
418
+ /**
419
+ * Get current session ID
420
+ * @return {string|null}
421
+ * @inner
422
+ */
423
+ getCurrentSessionId() {
424
+ return sessionId
425
+ },
401
426
  }
402
427
 
403
428
  function getTimeoutPromise(timeoutMs, taskName) {
package/lib/result.js CHANGED
@@ -3,22 +3,21 @@ import path from 'path'
3
3
  import { serializeTest } from './mocha/test.js'
4
4
 
5
5
  /**
6
- * Result of the test run
7
- *
8
- * @typedef {Object} Stats
9
- * @property {number} passes
10
- * @property {number} failures
11
- * @property {number} tests
12
- * @property {number} pending
13
- * @property {number} failedHooks
14
- * @property {Date} start
15
- * @property {Date} end
16
- * @property {number} duration
6
+ * @typedef {Object} Stats Statistics for a test result.
7
+ * @property {number} passes Number of passed tests.
8
+ * @property {number} failures Number of failed tests.
9
+ * @property {number} tests Total number of tests.
10
+ * @property {number} pending Number of pending tests.
11
+ * @property {number} failedHooks Number of failed hooks.
12
+ * @property {Date} start Start time of the test run.
13
+ * @property {Date} end End time of the test run.
14
+ * @property {number} duration Duration of the test run, in milliseconds.
15
+ */
16
+
17
+ /**
18
+ * Result of a test run. Will be emitted for example in "event.all.result" events.
17
19
  */
18
20
  class Result {
19
- /**
20
- * Create Result of the test run
21
- */
22
21
  constructor() {
23
22
  this._startTime = new Date()
24
23
  this._endTime = null
@@ -27,6 +26,9 @@ class Result {
27
26
  this.start()
28
27
  }
29
28
 
29
+ /**
30
+ * Resets all collected stats, tests, and failure reports.
31
+ */
30
32
  reset() {
31
33
  this._stats = {
32
34
  passes: 0,
@@ -39,43 +41,85 @@ class Result {
39
41
  duration: 0,
40
42
  }
41
43
 
42
- /** @type {CodeceptJS.Test[]} */
44
+ /**
45
+ * @type {CodeceptJS.Test[]}
46
+ * @private
47
+ */
43
48
  this._tests = []
44
49
 
45
- /** @type {String[]} */
50
+ /**
51
+ * @type {string[][]}
52
+ * @private
53
+ */
46
54
  this._failures = []
47
55
  }
48
56
 
57
+ /**
58
+ * Sets the start time to the current time.
59
+ */
49
60
  start() {
50
61
  this._startTime = new Date()
51
62
  }
52
63
 
64
+ /**
65
+ * Sets the end time to the current time.
66
+ */
53
67
  finish() {
54
68
  this._endTime = new Date()
55
69
  }
56
70
 
71
+ /**
72
+ * Whether this result contains any failed tests.
73
+ *
74
+ * @type {boolean}
75
+ * @readonly
76
+ */
57
77
  get hasFailed() {
58
78
  return this._stats.failures > 0
59
79
  }
60
80
 
81
+ /**
82
+ * All collected tests.
83
+ *
84
+ * @type {CodeceptJS.Test[]}
85
+ * @readonly
86
+ */
61
87
  get tests() {
62
88
  return this._tests
63
89
  }
64
90
 
91
+ /**
92
+ * The failure reports (array of strings per failed test).
93
+ *
94
+ * @type {string[][]}
95
+ * @readonly
96
+ */
65
97
  get failures() {
66
98
  return this._failures.filter(f => f && (!Array.isArray(f) || f.length > 0))
67
99
  }
68
100
 
101
+ /**
102
+ * The test statistics.
103
+ *
104
+ * @type {Stats}
105
+ * @readonly
106
+ */
69
107
  get stats() {
70
108
  return this._stats
71
109
  }
72
110
 
111
+ /**
112
+ * The start time of the test run.
113
+ *
114
+ * @type {Date}
115
+ * @readonly
116
+ */
73
117
  get startTime() {
74
118
  return this._startTime
75
119
  }
76
120
 
77
121
  /**
78
- * Add test to result
122
+ * Adds a test to this result.
79
123
  *
80
124
  * @param {CodeceptJS.Test} test
81
125
  */
@@ -90,34 +134,67 @@ class Result {
90
134
  }
91
135
 
92
136
  /**
93
- * Add failures to result
137
+ * Adds failure reports to this result.
94
138
  *
95
- * @param {String[]} newFailures
139
+ * @param {string[][]} newFailures
96
140
  */
97
141
  addFailures(newFailures) {
98
142
  this._failures.push(...newFailures)
99
143
  }
100
144
 
145
+ /**
146
+ * Whether this result contains any failed tests.
147
+ *
148
+ * @type {boolean}
149
+ * @readonly
150
+ */
101
151
  get hasFailures() {
102
152
  return this.stats.failures > 0
103
153
  }
104
154
 
155
+ /**
156
+ * The duration of the test run, in milliseconds.
157
+ *
158
+ * @type {number}
159
+ * @readonly
160
+ */
105
161
  get duration() {
106
162
  return this._endTime ? +this._endTime - +this._startTime : 0
107
163
  }
108
164
 
165
+ /**
166
+ * All failed tests.
167
+ *
168
+ * @type {CodeceptJS.Test[]}
169
+ * readonly
170
+ */
109
171
  get failedTests() {
110
172
  return this._tests.filter(test => test.state === 'failed')
111
173
  }
112
174
 
175
+ /**
176
+ * All passed tests.
177
+ *
178
+ * @type {CodeceptJS.Test[]}
179
+ * @readonly
180
+ */
113
181
  get passedTests() {
114
182
  return this._tests.filter(test => test.state === 'passed')
115
183
  }
116
184
 
185
+ /**
186
+ * All skipped tests.
187
+ *
188
+ * @type {CodeceptJS.Test[]}
189
+ * @readonly
190
+ */
117
191
  get skippedTests() {
118
192
  return this._tests.filter(test => test.state === 'skipped' || test.state === 'pending')
119
193
  }
120
194
 
195
+ /**
196
+ * @returns {object} The JSON representation of this result.
197
+ */
121
198
  simplify() {
122
199
  return {
123
200
  hasFailed: this.hasFailed,
@@ -129,9 +206,9 @@ class Result {
129
206
  }
130
207
 
131
208
  /**
132
- * Save result to json file
209
+ * Saves this result to a JSON file.
133
210
  *
134
- * @param {string} fileName
211
+ * @param {string} [fileName] Path to the JSON file, relative to `output_dir`. Defaults to "result.json".
135
212
  */
136
213
  save(fileName) {
137
214
  if (!fileName) fileName = 'result.json'
@@ -139,9 +216,9 @@ class Result {
139
216
  }
140
217
 
141
218
  /**
142
- * Add stats to result
219
+ * Adds stats to this result.
143
220
  *
144
- * @param {object} newStats
221
+ * @param {Partial<Stats>} [newStats]
145
222
  */
146
223
  addStats(newStats = {}) {
147
224
  this._stats.passes += newStats.passes || 0
@@ -0,0 +1,207 @@
1
+ import output from './output.js'
2
+
3
+ /**
4
+ * Retry Coordinator - Central coordination for all retry mechanisms
5
+ *
6
+ * This module provides:
7
+ * 1. Priority-based retry coordination
8
+ * 2. Unified configuration validation
9
+ * 3. Consolidated retry reporting
10
+ * 4. Conflict detection and resolution
11
+ */
12
+
13
+ /**
14
+ * Priority levels for retry mechanisms (higher number = higher priority)
15
+ */
16
+ const RETRY_PRIORITIES = {
17
+ MANUAL_STEP: 100, // I.retry() or step.retry() - highest priority
18
+ STEP_PLUGIN: 50, // retryFailedStep plugin
19
+ SCENARIO_CONFIG: 30, // Global scenario retry config
20
+ FEATURE_CONFIG: 20, // Global feature retry config
21
+ HOOK_CONFIG: 10, // Hook retry config - lowest priority
22
+ }
23
+
24
+ /**
25
+ * Retry mechanism types
26
+ */
27
+ const RETRY_TYPES = {
28
+ MANUAL_STEP: 'manual-step',
29
+ STEP_PLUGIN: 'step-plugin',
30
+ SCENARIO: 'scenario',
31
+ FEATURE: 'feature',
32
+ HOOK: 'hook',
33
+ }
34
+
35
+ /**
36
+ * Global retry coordination state
37
+ */
38
+ let retryState = {
39
+ activeTest: null,
40
+ activeSuite: null,
41
+ retryHistory: [],
42
+ conflicts: [],
43
+ }
44
+
45
+ /**
46
+ * Registers a retry mechanism for coordination
47
+ * @param {string} type - Type of retry mechanism
48
+ * @param {Object} config - Retry configuration
49
+ * @param {Object} target - Target object (test, suite, etc.)
50
+ * @param {number} priority - Priority level
51
+ */
52
+ function registerRetry(type, config, target, priority = 0) {
53
+ const retryInfo = {
54
+ type,
55
+ config,
56
+ target,
57
+ priority,
58
+ timestamp: Date.now(),
59
+ }
60
+
61
+ // Detect conflicts
62
+ const existingRetries = retryState.retryHistory.filter(r => r.target === target && r.type !== type && r.priority !== priority)
63
+
64
+ if (existingRetries.length > 0) {
65
+ const conflict = {
66
+ newRetry: retryInfo,
67
+ existingRetries: existingRetries,
68
+ resolved: false,
69
+ }
70
+ retryState.conflicts.push(conflict)
71
+ handleRetryConflict(conflict)
72
+ }
73
+
74
+ retryState.retryHistory.push(retryInfo)
75
+
76
+ output.log(`[Retry Coordinator] Registered ${type} retry (priority: ${priority})`)
77
+ }
78
+
79
+ /**
80
+ * Handles conflicts between retry mechanisms
81
+ * @param {Object} conflict - Conflict information
82
+ */
83
+ function handleRetryConflict(conflict) {
84
+ const { newRetry, existingRetries } = conflict
85
+
86
+ // Find highest priority retry
87
+ const allRetries = [newRetry, ...existingRetries]
88
+ const highestPriority = Math.max(...allRetries.map(r => r.priority))
89
+ const winningRetry = allRetries.find(r => r.priority === highestPriority)
90
+
91
+ // Log the conflict resolution
92
+ output.log(`[Retry Coordinator] Conflict detected:`)
93
+ allRetries.forEach(retry => {
94
+ const status = retry === winningRetry ? 'ACTIVE' : 'DEFERRED'
95
+ output.log(` - ${retry.type} (priority: ${retry.priority}) [${status}]`)
96
+ })
97
+
98
+ conflict.resolved = true
99
+ conflict.winner = winningRetry
100
+ }
101
+
102
+ /**
103
+ * Gets the effective retry configuration for a target
104
+ * @param {Object} target - Target object (test, suite, etc.)
105
+ * @returns {Object} Effective retry configuration
106
+ */
107
+ function getEffectiveRetryConfig(target) {
108
+ const targetRetries = retryState.retryHistory.filter(r => r.target === target)
109
+
110
+ if (targetRetries.length === 0) {
111
+ return { type: 'none', retries: 0 }
112
+ }
113
+
114
+ // Find highest priority retry
115
+ const highestPriority = Math.max(...targetRetries.map(r => r.priority))
116
+ const effectiveRetry = targetRetries.find(r => r.priority === highestPriority)
117
+
118
+ return {
119
+ type: effectiveRetry.type,
120
+ retries: effectiveRetry.config.retries || effectiveRetry.config,
121
+ config: effectiveRetry.config,
122
+ }
123
+ }
124
+
125
+ /**
126
+ * Generates a retry summary report
127
+ * @returns {Object} Retry summary
128
+ */
129
+ function generateRetrySummary() {
130
+ const summary = {
131
+ totalRetryMechanisms: retryState.retryHistory.length,
132
+ conflicts: retryState.conflicts.length,
133
+ byType: {},
134
+ recommendations: [],
135
+ }
136
+
137
+ // Count by type
138
+ retryState.retryHistory.forEach(retry => {
139
+ summary.byType[retry.type] = (summary.byType[retry.type] || 0) + 1
140
+ })
141
+
142
+ // Generate recommendations
143
+ if (summary.conflicts > 0) {
144
+ summary.recommendations.push('Consider consolidating retry configurations to avoid conflicts')
145
+ }
146
+
147
+ if (summary.byType[RETRY_TYPES.STEP_PLUGIN] && summary.byType[RETRY_TYPES.SCENARIO]) {
148
+ summary.recommendations.push('Step-level and scenario-level retries are both active - consider using only one approach')
149
+ }
150
+
151
+ return summary
152
+ }
153
+
154
+ /**
155
+ * Resets the retry coordination state (useful for testing)
156
+ */
157
+ function reset() {
158
+ retryState = {
159
+ activeTest: null,
160
+ activeSuite: null,
161
+ retryHistory: [],
162
+ conflicts: [],
163
+ }
164
+ }
165
+
166
+ /**
167
+ * Validates retry configuration for common issues
168
+ * @param {Object} config - Configuration object
169
+ * @returns {Array} Array of validation warnings
170
+ */
171
+ function validateConfig(config) {
172
+ const warnings = []
173
+
174
+ if (!config) return warnings
175
+
176
+ // Check for potential configuration conflicts
177
+ if (config.retry && config.plugins && config.plugins.retryFailedStep) {
178
+ const globalRetries = typeof config.retry === 'number' ? config.retry : config.retry.Scenario || config.retry.Feature
179
+ const stepRetries = config.plugins.retryFailedStep.retries || 3
180
+
181
+ if (globalRetries && stepRetries) {
182
+ warnings.push(`Both global retries (${globalRetries}) and step retries (${stepRetries}) are configured - total executions could be ${globalRetries * (stepRetries + 1)}`)
183
+ }
184
+ }
185
+
186
+ // Check for excessive retry counts
187
+ if (config.retry) {
188
+ const retryValues = typeof config.retry === 'number' ? [config.retry] : Object.values(config.retry)
189
+ const maxRetries = Math.max(...retryValues.filter(v => typeof v === 'number'))
190
+
191
+ if (maxRetries > 5) {
192
+ warnings.push(`High retry count detected (${maxRetries}) - consider investigating test stability instead`)
193
+ }
194
+ }
195
+
196
+ return warnings
197
+ }
198
+
199
+ export {
200
+ RETRY_PRIORITIES,
201
+ RETRY_TYPES,
202
+ registerRetry,
203
+ getEffectiveRetryConfig,
204
+ generateRetrySummary,
205
+ validateConfig,
206
+ reset,
207
+ }
package/lib/step/base.js CHANGED
@@ -225,7 +225,7 @@ class Step {
225
225
  processingStep = this
226
226
 
227
227
  while (processingStep.metaStep) {
228
- if (processingStep.metaStep.actor?.match(/^(Given|When|Then|And)/)) {
228
+ if (processingStep.metaStep.actor?.match(/^(Given|When|Then|And|But)/)) {
229
229
  hasBDD = true
230
230
  break
231
231
  } else {
@@ -1,4 +1,4 @@
1
- const FuncStep = require('./func')
1
+ import FuncStep from './func.js'
2
2
 
3
3
  class CommentStep extends FuncStep {
4
4
  constructor(name, comment) {
@@ -7,4 +7,4 @@ class CommentStep extends FuncStep {
7
7
  }
8
8
  }
9
9
 
10
- module.exports = CommentStep
10
+ export default CommentStep
package/lib/step/meta.js CHANGED
@@ -15,7 +15,7 @@ class MetaStep extends Step {
15
15
 
16
16
  /** @return {boolean} */
17
17
  isBDD() {
18
- if (this.actor && this.actor.match && this.actor.match(/^(Given|When|Then|And)/)) {
18
+ if (this.actor && this.actor.match && this.actor.match(/^(Given|When|Then|And|But)/)) {
19
19
  return true
20
20
  }
21
21
  return false
@@ -1,4 +1,4 @@
1
- const { heal, ai } = require('codeceptjs')
1
+ import { heal, ai } from 'codeceptjs'
2
2
 
3
3
  heal.addRecipe('ai', {
4
4
  priority: 10,
@@ -0,0 +1,31 @@
1
+ export default (html, extraPrompt = '', rootLocator = null) => [
2
+ {
3
+ role: 'user',
4
+ content: `As a test automation engineer I am creating a Page Object for a web application using CodeceptJS.
5
+ Here is an sample page object:
6
+
7
+ const { I } = inject();
8
+
9
+ export default {
10
+
11
+ // setting locators
12
+ element1: '#selector',
13
+ element2: '.selector',
14
+ element3: locate().withText('text'),
15
+
16
+ // setting methods
17
+ doSomethingOnPage(params) {
18
+ // ...
19
+ },
20
+ }
21
+
22
+ I want to generate a Page Object for the page I provide.
23
+ Write JavaScript code in similar manner to list all locators on the page.
24
+ Use locators in order of preference: by text (use locate().withText()), label, CSS, XPath.
25
+ Avoid TailwindCSS, Bootstrap or React style formatting classes in locators.
26
+ Add methods to interact with page when needed.
27
+ ${extraPrompt}
28
+ ${rootLocator ? `All provided elements are inside '${rootLocator}'. Declare it as root variable and for every locator use locate(...).inside(root)` : ''}
29
+ Add only locators from this HTML: \n\n${html}`,
30
+ },
31
+ ]
@@ -0,0 +1,13 @@
1
+ export default (html, { step, error, prevSteps }) => {
2
+ return [
3
+ {
4
+ role: 'user',
5
+ content: `As a test automation engineer I am testing web application using CodeceptJS.
6
+ I want to heal a test that fails. Here is the list of executed steps: ${prevSteps.map(s => s.toString()).join(', ')}
7
+ Propose how to adjust ${step.toCode()} step to fix the test.
8
+ Use locators in order of preference: semantic locator by text, CSS, XPath. Use codeblocks marked with \`\`\`
9
+ Here is the error message: ${error.message}
10
+ Here is HTML code of a page where the failure has happened: \n\n${html}`,
11
+ },
12
+ ]
13
+ }
@@ -0,0 +1,9 @@
1
+ export default (html, input) => [
2
+ {
3
+ role: 'user',
4
+ content: `I am test engineer writing test in CodeceptJS
5
+ I have opened web page and I want to use CodeceptJS to ${input} on this page
6
+ Provide me valid CodeceptJS code to accomplish it
7
+ Use only locators from this HTML: \n\n${html}`,
8
+ },
9
+ ]