codeceptjs 4.0.0-beta.1 → 4.0.0-beta.10.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 (207) 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 +238 -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 +300 -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 +124 -50
  39. package/lib/container.js +751 -260
  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/mask_data.js +47 -0
  157. package/lib/utils.js +411 -228
  158. package/lib/workerStorage.js +37 -34
  159. package/lib/workers.js +532 -296
  160. package/package.json +115 -95
  161. package/translations/de-DE.js +5 -3
  162. package/translations/fr-FR.js +5 -4
  163. package/translations/index.js +22 -12
  164. package/translations/it-IT.js +4 -3
  165. package/translations/ja-JP.js +4 -3
  166. package/translations/nl-NL.js +76 -0
  167. package/translations/pl-PL.js +4 -3
  168. package/translations/pt-BR.js +4 -3
  169. package/translations/ru-RU.js +4 -3
  170. package/translations/utils.js +10 -0
  171. package/translations/zh-CN.js +4 -3
  172. package/translations/zh-TW.js +4 -3
  173. package/typings/index.d.ts +546 -185
  174. package/typings/promiseBasedTypes.d.ts +150 -879
  175. package/typings/types.d.ts +547 -996
  176. package/lib/cli.js +0 -249
  177. package/lib/dirname.js +0 -5
  178. package/lib/helper/Expect.js +0 -425
  179. package/lib/helper/ExpectHelper.js +0 -399
  180. package/lib/helper/MockServer.js +0 -223
  181. package/lib/helper/Nightmare.js +0 -1411
  182. package/lib/helper/Protractor.js +0 -1835
  183. package/lib/helper/SoftExpectHelper.js +0 -381
  184. package/lib/helper/TestCafe.js +0 -1410
  185. package/lib/helper/clientscripts/nightmare.js +0 -213
  186. package/lib/helper/testcafe/testControllerHolder.js +0 -42
  187. package/lib/helper/testcafe/testcafe-utils.js +0 -63
  188. package/lib/interfaces/bdd.js +0 -98
  189. package/lib/interfaces/featureConfig.js +0 -69
  190. package/lib/interfaces/gherkin.js +0 -195
  191. package/lib/listener/artifacts.js +0 -19
  192. package/lib/listener/retry.js +0 -68
  193. package/lib/listener/timeout.js +0 -109
  194. package/lib/mochaFactory.js +0 -110
  195. package/lib/plugin/allure.js +0 -15
  196. package/lib/plugin/commentStep.js +0 -136
  197. package/lib/plugin/debugErrors.js +0 -67
  198. package/lib/plugin/eachElement.js +0 -127
  199. package/lib/plugin/fakerTransform.js +0 -49
  200. package/lib/plugin/retryTo.js +0 -121
  201. package/lib/plugin/selenoid.js +0 -371
  202. package/lib/plugin/standardActingHelpers.js +0 -9
  203. package/lib/plugin/tryTo.js +0 -105
  204. package/lib/plugin/wdio.js +0 -246
  205. package/lib/scenario.js +0 -222
  206. package/lib/ui.js +0 -238
  207. package/lib/within.js +0 -70
@@ -1,12 +1,6 @@
1
- import joi from 'joi';
2
- import Helper from '../helper.js';
3
-
4
- let expect;
5
-
6
- import('chai').then(chai => {
7
- expect = chai.expect;
8
- chai.use(require('chai-deep-match'));
9
- });
1
+ import Helper from '@codeceptjs/helper'
2
+ import assert from 'assert'
3
+ import { z } from 'zod'
10
4
 
11
5
  /**
12
6
  * This helper allows performing assertions on JSON responses paired with following helpers:
@@ -66,36 +60,30 @@ import('chai').then(chai => {
66
60
  */
67
61
  class JSONResponse extends Helper {
68
62
  constructor(config = {}) {
69
- super(config);
63
+ super(config)
70
64
  this.options = {
71
65
  requestHelper: 'REST',
72
- };
73
- this.options = { ...this.options, ...config };
66
+ }
67
+ this.options = { ...this.options, ...config }
74
68
  }
75
69
 
76
70
  _beforeSuite() {
77
- this.response = null;
71
+ this.response = null
78
72
  if (!this.helpers[this.options.requestHelper]) {
79
- throw new Error(`Error setting JSONResponse, helper ${this.options.requestHelper} is not enabled in config, helpers: ${Object.keys(this.helpers)}`);
73
+ throw new Error(`Error setting JSONResponse, helper ${this.options.requestHelper} is not enabled in config, helpers: ${Object.keys(this.helpers)}`)
74
+ }
75
+ const origOnResponse = this.helpers[this.options.requestHelper].config.onResponse
76
+ this.helpers[this.options.requestHelper].config.onResponse = response => {
77
+ this.response = response
78
+ if (typeof origOnResponse === 'function') origOnResponse(response)
80
79
  }
81
- // connect to REST helper
82
- this.helpers[this.options.requestHelper].config.onResponse = (response) => {
83
- this.response = response;
84
- };
85
80
  }
86
81
 
87
82
  _before() {
88
- this.response = null;
89
- }
90
-
91
- static _checkRequirements() {
92
- try {
93
- require('joi');
94
- } catch (e) {
95
- return ['joi'];
96
- }
83
+ this.response = null
97
84
  }
98
85
 
86
+
99
87
  /**
100
88
  * Checks that response code is equal to the provided one
101
89
  *
@@ -106,8 +94,8 @@ class JSONResponse extends Helper {
106
94
  * @param {number} code
107
95
  */
108
96
  seeResponseCodeIs(code) {
109
- this._checkResponseReady();
110
- expect(this.response.status).to.eql(code, 'Response code is not the same as expected');
97
+ this._checkResponseReady()
98
+ assert.strictEqual(this.response.status, code, 'Response code is not the same as expected')
111
99
  }
112
100
 
113
101
  /**
@@ -120,35 +108,32 @@ class JSONResponse extends Helper {
120
108
  * @param {number} code
121
109
  */
122
110
  dontSeeResponseCodeIs(code) {
123
- this._checkResponseReady();
124
- expect(this.response.status).not.to.eql(code);
111
+ this._checkResponseReady()
112
+ assert.notStrictEqual(this.response.status, code)
125
113
  }
126
114
 
127
115
  /**
128
116
  * Checks that the response code is 4xx
129
117
  */
130
118
  seeResponseCodeIsClientError() {
131
- this._checkResponseReady();
132
- expect(this.response.status).to.be.gte(400);
133
- expect(this.response.status).to.be.lt(500);
119
+ this._checkResponseReady()
120
+ assert(this.response.status >= 400 && this.response.status < 500)
134
121
  }
135
122
 
136
123
  /**
137
124
  * Checks that the response code is 3xx
138
125
  */
139
126
  seeResponseCodeIsRedirection() {
140
- this._checkResponseReady();
141
- expect(this.response.status).to.be.gte(300);
142
- expect(this.response.status).to.be.lt(400);
127
+ this._checkResponseReady()
128
+ assert(this.response.status >= 300 && this.response.status < 400)
143
129
  }
144
130
 
145
131
  /**
146
132
  * Checks that the response code is 5xx
147
133
  */
148
134
  seeResponseCodeIsServerError() {
149
- this._checkResponseReady();
150
- expect(this.response.status).to.be.gte(500);
151
- expect(this.response.status).to.be.lt(600);
135
+ this._checkResponseReady()
136
+ assert(this.response.status >= 500 && this.response.status < 600)
152
137
  }
153
138
 
154
139
  /**
@@ -160,9 +145,8 @@ class JSONResponse extends Helper {
160
145
  * ```
161
146
  */
162
147
  seeResponseCodeIsSuccessful() {
163
- this._checkResponseReady();
164
- expect(this.response.status).to.be.gte(200);
165
- expect(this.response.status).to.be.lt(300);
148
+ this._checkResponseReady()
149
+ assert(this.response.status >= 200 && this.response.status < 300)
166
150
  }
167
151
 
168
152
  /**
@@ -183,19 +167,21 @@ class JSONResponse extends Helper {
183
167
  * @param {object} json
184
168
  */
185
169
  seeResponseContainsJson(json = {}) {
186
- this._checkResponseReady();
170
+ this._checkResponseReady()
187
171
  if (Array.isArray(this.response.data)) {
188
- let fails = 0;
172
+ let found = false
189
173
  for (const el of this.response.data) {
190
174
  try {
191
- expect(el).to.deep.match(json);
175
+ this._assertContains(el, json)
176
+ found = true
177
+ break
192
178
  } catch (err) {
193
- fails++;
179
+ continue
194
180
  }
195
181
  }
196
- expect(fails < this.response.data.length, `No elements in array matched ${JSON.stringify(json)}`).to.be.true;
182
+ assert(found, `No elements in array matched ${JSON.stringify(json)}`)
197
183
  } else {
198
- expect(this.response.data).to.deep.match(json);
184
+ this._assertContains(this.response.data, json)
199
185
  }
200
186
  }
201
187
 
@@ -217,11 +203,24 @@ class JSONResponse extends Helper {
217
203
  * @param {object} json
218
204
  */
219
205
  dontSeeResponseContainsJson(json = {}) {
220
- this._checkResponseReady();
206
+ this._checkResponseReady()
221
207
  if (Array.isArray(this.response.data)) {
222
- this.response.data.forEach(data => expect(data).not.to.deep.match(json));
208
+ for (const data of this.response.data) {
209
+ try {
210
+ this._assertContains(data, json)
211
+ assert.fail(`Found matching element: ${JSON.stringify(data)}`)
212
+ } catch (err) {
213
+ // expected to fail
214
+ continue
215
+ }
216
+ }
223
217
  } else {
224
- expect(this.response.data).not.to.deep.match(json);
218
+ try {
219
+ this._assertContains(this.response.data, json)
220
+ assert.fail('Response contains the JSON')
221
+ } catch (err) {
222
+ // expected to fail
223
+ }
225
224
  }
226
225
  }
227
226
 
@@ -245,32 +244,39 @@ class JSONResponse extends Helper {
245
244
  * @param {array} keys
246
245
  */
247
246
  seeResponseContainsKeys(keys = []) {
248
- this._checkResponseReady();
247
+ this._checkResponseReady()
249
248
  if (Array.isArray(this.response.data)) {
250
- this.response.data.forEach(data => expect(data).to.include.keys(keys));
249
+ for (const data of this.response.data) {
250
+ for (const key of keys) {
251
+ assert(key in data, `Key "${key}" is not found in ${JSON.stringify(data)}`)
252
+ }
253
+ }
251
254
  } else {
252
- expect(this.response.data).to.include.keys(keys);
255
+ for (const key of keys) {
256
+ assert(key in this.response.data, `Key "${key}" is not found in ${JSON.stringify(this.response.data)}`)
257
+ }
253
258
  }
254
259
  }
255
260
 
256
261
  /**
257
- * Executes a callback function passing in `response` object and chai assertions with `expect`
262
+ * Executes a callback function passing in `response` object and assert
258
263
  * Use it to perform custom checks of response data
259
264
  *
260
265
  * ```js
261
- * I.seeResponseValidByCallback(({ data, status, expect }) => {
262
- * expect(status).to.eql(200);
263
- * expect(data).keys.to.include(['user', 'company']);
266
+ * I.seeResponseValidByCallback(({ data, status }) => {
267
+ * assert.strictEqual(status, 200);
268
+ * assert('user' in data);
269
+ * assert('company' in data);
264
270
  * });
265
271
  * ```
266
272
  *
267
273
  * @param {function} fn
268
274
  */
269
275
  seeResponseValidByCallback(fn) {
270
- this._checkResponseReady();
271
- fn({ ...this.response, expect });
272
- const body = fn.toString();
273
- fn.toString = () => `${body.split('\n')[1]}...`;
276
+ this._checkResponseReady()
277
+ fn({ ...this.response, assert })
278
+ const body = fn.toString()
279
+ fn.toString = () => `${body.split('\n')[1]}...`
274
280
  }
275
281
 
276
282
  /**
@@ -284,54 +290,86 @@ class JSONResponse extends Helper {
284
290
  * @param {object} resp
285
291
  */
286
292
  seeResponseEquals(resp) {
287
- this._checkResponseReady();
288
- expect(this.response.data).to.deep.equal(resp);
293
+ this._checkResponseReady()
294
+ assert.deepStrictEqual(this.response.data, resp)
289
295
  }
290
296
 
291
297
  /**
292
- * Validates JSON structure of response using [joi library](https://joi.dev).
293
- * See [joi API](https://joi.dev/api/) for complete reference on usage.
298
+ * Validates JSON structure of response using [Zod library](https://zod.dev).
299
+ * See [Zod API](https://zod.dev/) for complete reference on usage.
294
300
  *
295
- * Use pre-initialized joi instance by passing function callback:
301
+ * Use pre-initialized Zod instance by passing function callback:
296
302
  *
297
303
  * ```js
298
304
  * // response.data is { name: 'jon', id: 1 }
299
305
  *
300
- * I.seeResponseMatchesJsonSchema(joi => {
301
- * return joi.object({
302
- * name: joi.string(),
303
- * id: joi.number()
306
+ * I.seeResponseMatchesJsonSchema(z => {
307
+ * return z.object({
308
+ * name: z.string(),
309
+ * id: z.number()
304
310
  * })
305
311
  * });
306
312
  *
307
313
  * // or pass a valid schema
308
- * const joi = require('joi');
314
+ * import { z } from 'zod';
309
315
  *
310
- * I.seeResponseMatchesJsonSchema(joi.object({
311
- * name: joi.string(),
312
- * id: joi.number();
313
- * });
316
+ * I.seeResponseMatchesJsonSchema(z.object({
317
+ * name: z.string(),
318
+ * id: z.number()
319
+ * }));
314
320
  * ```
315
321
  *
316
322
  * @param {any} fnOrSchema
317
323
  */
318
324
  seeResponseMatchesJsonSchema(fnOrSchema) {
319
- this._checkResponseReady();
320
- let schema = fnOrSchema;
325
+ this._checkResponseReady()
326
+ let schema = fnOrSchema
321
327
  if (typeof fnOrSchema === 'function') {
322
- schema = fnOrSchema(joi);
323
- const body = fnOrSchema.toString();
324
- fnOrSchema.toString = () => `${body.split('\n')[1]}...`;
328
+ schema = fnOrSchema(z)
329
+ const body = fnOrSchema.toString()
330
+ fnOrSchema.toString = () => `${body.split('\n')[1]}...`
331
+ }
332
+ if (!schema) throw new Error('Empty Zod schema provided, see https://zod.dev/ for details')
333
+ if (!(schema instanceof z.ZodType)) throw new Error('Invalid Zod schema provided, see https://zod.dev/ for details')
334
+ schema.toString = () => schema._def.description || JSON.stringify(schema._def)
335
+ const result = schema.parse(this.response.data)
336
+ if (!result) {
337
+ throw new Error('Schema validation failed')
325
338
  }
326
- if (!schema) throw new Error('Empty Joi schema provided, see https://joi.dev/ for details');
327
- if (!joi.isSchema(schema)) throw new Error('Invalid Joi schema provided, see https://joi.dev/ for details');
328
- schema.toString = () => schema.describe();
329
- joi.assert(this.response.data, schema);
330
339
  }
331
340
 
332
341
  _checkResponseReady() {
333
- if (!this.response) throw new Error('Response is not available');
342
+ if (!this.response) throw new Error('Response is not available')
343
+ }
344
+
345
+ _assertContains(actual, expected) {
346
+ for (const key in expected) {
347
+ assert(key in actual, `Key "${key}" not found in ${JSON.stringify(actual)}`)
348
+ if (typeof expected[key] === 'object' && expected[key] !== null) {
349
+ if (Array.isArray(expected[key])) {
350
+ // Handle array comparison: each expected element should have a match in actual array
351
+ assert(Array.isArray(actual[key]), `Expected array for key "${key}", but got ${typeof actual[key]}`)
352
+ for (const expectedItem of expected[key]) {
353
+ let found = false
354
+ for (const actualItem of actual[key]) {
355
+ try {
356
+ this._assertContains(actualItem, expectedItem)
357
+ found = true
358
+ break
359
+ } catch (err) {
360
+ continue
361
+ }
362
+ }
363
+ assert(found, `No matching element found in array for ${JSON.stringify(expectedItem)}`)
364
+ }
365
+ } else {
366
+ this._assertContains(actual[key], expected[key])
367
+ }
368
+ } else {
369
+ assert.deepStrictEqual(actual[key], expected[key], `Values for key "${key}" don't match`)
370
+ }
371
+ }
334
372
  }
335
373
  }
336
374
 
337
- export default JSONResponse;
375
+ export { JSONResponse as default }
@@ -1,71 +1,96 @@
1
- import Helper from '@codeceptjs/helper';
2
- import { clearString } from '../utils.js';
1
+ let currentTest
2
+ let currentSuite
3
3
 
4
- let addMochawesomeContext;
5
- let currentTest;
6
- let currentSuite;
4
+ import Helper from '@codeceptjs/helper'
5
+ import { createRequire } from 'module'
6
+ import { clearString } from '../utils.js'
7
+ import { testToFileName } from '../mocha/test.js'
7
8
 
8
9
  class Mochawesome extends Helper {
9
10
  constructor(config) {
10
- super(config);
11
+ super(config)
11
12
 
12
13
  // set defaults
13
14
  this.options = {
14
15
  uniqueScreenshotNames: false,
15
16
  disableScreenshots: false,
16
- };
17
+ }
18
+
19
+ // ESM-compatible require for CommonJS module
20
+ const require = createRequire(import.meta.url)
21
+ this._addContext = require('mochawesome/addContext')
17
22
 
18
- addMochawesomeContext = require('mochawesome/addContext');
19
- this._createConfig(config);
23
+ this._createConfig(config)
20
24
  }
21
25
 
22
26
  _createConfig(config) {
23
27
  // override defaults with config
24
- Object.assign(this.options, config);
28
+ Object.assign(this.options, config)
25
29
  }
26
30
 
27
31
  _beforeSuite(suite) {
28
- currentSuite = suite;
29
- currentTest = '';
32
+ currentSuite = suite
33
+ currentTest = ''
30
34
  }
31
35
 
32
36
  _before() {
33
37
  if (currentSuite && currentSuite.ctx) {
34
- currentTest = { test: currentSuite.ctx.currentTest };
38
+ currentTest = { test: currentSuite.ctx.currentTest }
35
39
  }
36
40
  }
37
41
 
38
42
  _test(test) {
39
- currentTest = { test };
43
+ // If this is a retried test, we want to add context to the retried test
44
+ // but also potentially preserve context from the original test
45
+ const originalTest = test.retriedTest && test.retriedTest()
46
+ if (originalTest) {
47
+ // This is a retried test - use the retried test for context
48
+ currentTest = { test }
49
+
50
+ // Optionally copy context from original test if it exists
51
+ // Note: mochawesome context is stored in test.ctx, but we need to be careful
52
+ // not to break the mocha context structure
53
+ } else {
54
+ // Normal test (not a retry)
55
+ currentTest = { test }
56
+ }
40
57
  }
41
58
 
42
59
  _failed(test) {
43
- if (this.options.disableScreenshots) return;
44
- let fileName;
60
+ if (this.options.disableScreenshots) return
61
+ let fileName
45
62
  // Get proper name if we are fail on hook
46
- if (test.ctx.test.type === 'hook') {
47
- currentTest = { test: test.ctx.test };
63
+ if (test.ctx?.test?.type === 'hook') {
64
+ currentTest = { test: test.ctx.test }
48
65
  // ignore retries if we are in hook
49
- test._retries = -1;
50
- fileName = clearString(`${test.title}_${currentTest.test.title}`);
66
+ test._retries = -1
67
+ fileName = clearString(`${test.title}_${currentTest.test.title}`)
51
68
  } else {
52
- currentTest = { test };
53
- fileName = clearString(test.title);
69
+ currentTest = { test }
70
+ fileName = testToFileName(test)
54
71
  }
55
72
  if (this.options.uniqueScreenshotNames) {
56
- const uuid = test.uuid || test.ctx.test.uuid;
57
- fileName = `${fileName.substring(0, 10)}_${uuid}`;
73
+ fileName = testToFileName(test, { unique: true })
58
74
  }
59
75
  if (test._retries < 1 || test._retries === test.retryNum) {
60
- fileName = `${fileName}.failed.png`;
61
- return addMochawesomeContext(currentTest, fileName);
76
+ fileName = `${fileName}.failed.png`
77
+ return this._addContext(currentTest, fileName)
62
78
  }
63
79
  }
64
80
 
65
81
  addMochawesomeContext(context) {
66
- if (currentTest === '') currentTest = { test: currentSuite.ctx.test };
67
- return addMochawesomeContext(currentTest, context);
82
+ if (currentTest === '') currentTest = { test: currentSuite.ctx.test }
83
+
84
+ // For retried tests, make sure we're adding context to the current (retried) test
85
+ // not the original test
86
+ let targetTest = currentTest
87
+ if (currentTest.test && currentTest.test.retriedTest && currentTest.test.retriedTest()) {
88
+ // This test has been retried, make sure we're using the current test for context
89
+ targetTest = { test: currentTest.test }
90
+ }
91
+
92
+ return this._addContext(targetTest, context)
68
93
  }
69
94
  }
70
95
 
71
- export default Mochawesome;
96
+ export default Mochawesome