codeceptjs 4.0.1-beta.3 → 4.0.1-beta.5

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.
@@ -87,8 +87,8 @@ class GraphQL extends Helper {
87
87
 
88
88
  request.headers = { ...this.headers, ...request.headers }
89
89
 
90
- if (this.config.onRequest) {
91
- await this.config.onRequest(request)
90
+ if (this.options.onRequest) {
91
+ await this.options.onRequest(request)
92
92
  }
93
93
 
94
94
  this.debugSection('Request', JSON.stringify(request))
@@ -102,8 +102,8 @@ class GraphQL extends Helper {
102
102
  response = err.response
103
103
  }
104
104
 
105
- if (this.config.onResponse) {
106
- await this.config.onResponse(response)
105
+ if (this.options.onResponse) {
106
+ await this.options.onResponse(response)
107
107
  }
108
108
 
109
109
  this.debugSection('Response', JSON.stringify(response.data))
@@ -72,8 +72,8 @@ class JSONResponse extends Helper {
72
72
  if (!this.helpers[this.options.requestHelper]) {
73
73
  throw new Error(`Error setting JSONResponse, helper ${this.options.requestHelper} is not enabled in config, helpers: ${Object.keys(this.helpers)}`)
74
74
  }
75
- const origOnResponse = this.helpers[this.options.requestHelper].config.onResponse
76
- this.helpers[this.options.requestHelper].config.onResponse = response => {
75
+ const origOnResponse = this.helpers[this.options.requestHelper].options.onResponse
76
+ this.helpers[this.options.requestHelper].options.onResponse = response => {
77
77
  this.response = response
78
78
  if (typeof origOnResponse === 'function') origOnResponse(response)
79
79
  }
@@ -83,7 +83,6 @@ class JSONResponse extends Helper {
83
83
  this.response = null
84
84
  }
85
85
 
86
-
87
86
  /**
88
87
  * Checks that response code is equal to the provided one
89
88
  *
@@ -372,4 +371,4 @@ class JSONResponse extends Helper {
372
371
  }
373
372
  }
374
373
 
375
- export { JSONResponse as default }
374
+ export { JSONResponse, JSONResponse as default }
@@ -355,7 +355,7 @@ class Playwright extends Helper {
355
355
  this.recordingWebSocketMessages = false
356
356
  this.recordedWebSocketMessagesAtLeastOnce = false
357
357
  this.cdpSession = null
358
-
358
+
359
359
  // Filter out invalid customLocatorStrategies (empty arrays, objects without functions)
360
360
  // This can happen in worker threads where config is serialized/deserialized
361
361
  let validCustomLocators = null
@@ -367,7 +367,7 @@ class Playwright extends Helper {
367
367
  validCustomLocators = config.customLocatorStrategies
368
368
  }
369
369
  }
370
-
370
+
371
371
  this.customLocatorStrategies = validCustomLocators
372
372
  this._customLocatorsRegistered = false
373
373
 
@@ -794,10 +794,7 @@ class Playwright extends Helper {
794
794
  await Promise.allSettled(pages.map(p => p.close().catch(() => {})))
795
795
  }
796
796
  // Use timeout to prevent hanging (10s should be enough for browser cleanup)
797
- await Promise.race([
798
- this._stopBrowser(),
799
- new Promise((_, reject) => setTimeout(() => reject(new Error('Browser stop timeout')), 10000)),
800
- ])
797
+ await Promise.race([this._stopBrowser(), new Promise((_, reject) => setTimeout(() => reject(new Error('Browser stop timeout')), 10000))])
801
798
  } catch (e) {
802
799
  console.warn('Warning during browser restart in _after:', e.message)
803
800
  // Force cleanup even on timeout
@@ -840,10 +837,7 @@ class Playwright extends Helper {
840
837
  if (this.isRunning) {
841
838
  try {
842
839
  // Add timeout protection to prevent hanging
843
- await Promise.race([
844
- this._stopBrowser(),
845
- new Promise((_, reject) => setTimeout(() => reject(new Error('Browser stop timeout in afterSuite')), 10000)),
846
- ])
840
+ await Promise.race([this._stopBrowser(), new Promise((_, reject) => setTimeout(() => reject(new Error('Browser stop timeout in afterSuite')), 10000))])
847
841
  } catch (e) {
848
842
  console.warn('Warning during suite cleanup:', e.message)
849
843
  // Track suite cleanup failures
@@ -954,10 +948,7 @@ class Playwright extends Helper {
954
948
  if (this.isRunning) {
955
949
  try {
956
950
  // Add timeout protection to prevent hanging
957
- await Promise.race([
958
- this._stopBrowser(),
959
- new Promise((_, reject) => setTimeout(() => reject(new Error('Browser stop timeout in cleanup')), 10000)),
960
- ])
951
+ await Promise.race([this._stopBrowser(), new Promise((_, reject) => setTimeout(() => reject(new Error('Browser stop timeout in cleanup')), 10000))])
961
952
  } catch (e) {
962
953
  console.warn('Warning during final cleanup:', e.message)
963
954
  // Force cleanup on timeout
@@ -970,10 +961,7 @@ class Playwright extends Helper {
970
961
  if (this.browser) {
971
962
  try {
972
963
  // Add timeout protection to prevent hanging
973
- await Promise.race([
974
- this._stopBrowser(),
975
- new Promise((_, reject) => setTimeout(() => reject(new Error('Browser stop timeout in forced cleanup')), 10000)),
976
- ])
964
+ await Promise.race([this._stopBrowser(), new Promise((_, reject) => setTimeout(() => reject(new Error('Browser stop timeout in forced cleanup')), 10000))])
977
965
  } catch (e) {
978
966
  console.warn('Warning during forced cleanup:', e.message)
979
967
  // Force cleanup on timeout
@@ -1390,7 +1378,7 @@ class Playwright extends Helper {
1390
1378
  this.context = null
1391
1379
  this.frame = null
1392
1380
  popupStore.clear()
1393
-
1381
+
1394
1382
  // Remove all event listeners to prevent hanging
1395
1383
  if (this.browser) {
1396
1384
  try {
@@ -1399,7 +1387,7 @@ class Playwright extends Helper {
1399
1387
  // Ignore errors if browser is already closed
1400
1388
  }
1401
1389
  }
1402
-
1390
+
1403
1391
  if (this.options.recordHar && this.browserContext) {
1404
1392
  try {
1405
1393
  await this.browserContext.close()
@@ -1408,16 +1396,11 @@ class Playwright extends Helper {
1408
1396
  }
1409
1397
  }
1410
1398
  this.browserContext = null
1411
-
1399
+
1412
1400
  if (this.browser) {
1413
1401
  try {
1414
1402
  // Add timeout to prevent browser.close() from hanging indefinitely
1415
- await Promise.race([
1416
- this.browser.close(),
1417
- new Promise((_, reject) =>
1418
- setTimeout(() => reject(new Error('Browser close timeout')), 5000)
1419
- )
1420
- ])
1403
+ await Promise.race([this.browser.close(), new Promise((_, reject) => setTimeout(() => reject(new Error('Browser close timeout')), 5000))])
1421
1404
  } catch (e) {
1422
1405
  // Ignore errors if browser is already closed or timeout
1423
1406
  if (!e.message?.includes('Browser close timeout')) {
@@ -1539,7 +1522,7 @@ class Playwright extends Helper {
1539
1522
  acceptDownloads: true,
1540
1523
  ...this.options.emulate,
1541
1524
  }
1542
-
1525
+
1543
1526
  try {
1544
1527
  this.browserContext = await this.browser.newContext(contextOptions)
1545
1528
  } catch (err) {
@@ -3183,14 +3166,14 @@ class Playwright extends Helper {
3183
3166
  this.debugSection('Response', await response.text())
3184
3167
 
3185
3168
  // hook to allow JSON response handle this
3186
- if (this.config.onResponse) {
3169
+ if (this.options.onResponse) {
3187
3170
  const axiosResponse = {
3188
3171
  data: await response.json(),
3189
3172
  status: response.status(),
3190
3173
  statusText: response.statusText(),
3191
3174
  headers: response.headers(),
3192
3175
  }
3193
- this.config.onResponse(axiosResponse)
3176
+ this.options.onResponse(axiosResponse)
3194
3177
  }
3195
3178
 
3196
3179
  return response
@@ -4337,11 +4320,11 @@ function isRoleLocatorObject(locator) {
4337
4320
  */
4338
4321
  async function handleRoleLocator(context, locator) {
4339
4322
  if (!isRoleLocatorObject(locator)) return null
4340
-
4323
+
4341
4324
  const options = {}
4342
4325
  if (locator.text) options.name = locator.text
4343
4326
  if (locator.exact !== undefined) options.exact = locator.exact
4344
-
4327
+
4345
4328
  return context.getByRole(locator.role, Object.keys(options).length > 0 ? options : undefined).all()
4346
4329
  }
4347
4330
 
@@ -4350,7 +4333,7 @@ async function findElements(matcher, locator) {
4350
4333
  const isReactLocator = locator.type === 'react' || (locator.locator && locator.locator.react) || locator.react
4351
4334
  const isVueLocator = locator.type === 'vue' || (locator.locator && locator.locator.vue) || locator.vue
4352
4335
  const isPwLocator = locator.type === 'pw' || (locator.locator && locator.locator.pw) || locator.pw
4353
-
4336
+
4354
4337
  if (isReactLocator) return findReact(matcher, locator)
4355
4338
  if (isVueLocator) return findVue(matcher, locator)
4356
4339
  if (isPwLocator) return findByPlaywrightLocator.call(this, matcher, locator)
@@ -4391,7 +4374,7 @@ async function findCustomElements(matcher, locator) {
4391
4374
  // Always prioritize this.customLocatorStrategies which is set in constructor from config
4392
4375
  // and persists in every worker thread instance
4393
4376
  let strategyFunction = null
4394
-
4377
+
4395
4378
  if (this.customLocatorStrategies && this.customLocatorStrategies[locator.type]) {
4396
4379
  strategyFunction = this.customLocatorStrategies[locator.type]
4397
4380
  } else if (globalCustomLocatorStrategies.has(locator.type)) {
@@ -4967,7 +4950,7 @@ async function refreshContextSession() {
4967
4950
  this.debugSection('Session', 'Skipping storage cleanup - no active page/context')
4968
4951
  return
4969
4952
  }
4970
-
4953
+
4971
4954
  const currentUrl = await this.grabCurrentUrl()
4972
4955
 
4973
4956
  if (currentUrl.startsWith('http')) {
@@ -215,8 +215,8 @@ class REST extends Helper {
215
215
  }
216
216
  }
217
217
 
218
- if (this.config.onRequest) {
219
- await this.config.onRequest(request)
218
+ if (this.options.onRequest) {
219
+ await this.options.onRequest(request)
220
220
  }
221
221
 
222
222
  try {
@@ -245,8 +245,8 @@ class REST extends Helper {
245
245
  }
246
246
  response = err.response
247
247
  }
248
- if (this.config.onResponse) {
249
- await this.config.onResponse(response)
248
+ if (this.options.onResponse) {
249
+ await this.options.onResponse(response)
250
250
  }
251
251
  try {
252
252
  this.options.prettyPrintJson ? this.debugSection('Response', beautify(JSON.stringify(response.data))) : this.debugSection('Response', JSON.stringify(response.data))
@@ -12,15 +12,23 @@ export default function () {
12
12
  return
13
13
  }
14
14
  global.__codeceptConfigListenerInitialized = true
15
-
16
- const helpers = global.container.helpers()
17
15
 
18
16
  enableDynamicConfigFor('suite')
19
17
  enableDynamicConfigFor('test')
20
18
 
21
19
  function enableDynamicConfigFor(type) {
22
20
  event.dispatcher.on(event[type].before, (context = {}) => {
21
+ // Get helpers dynamically at runtime, not at initialization time
22
+ // This ensures we get the actual helper instances, not placeholders
23
+ const helpers = global.container.helpers()
24
+
23
25
  function updateHelperConfig(helper, config) {
26
+ // Guard against undefined or invalid helpers
27
+ if (!helper || !helper.constructor) {
28
+ output.debug(`[${ucfirst(type)} Config] Helper not found or not properly initialized`)
29
+ return
30
+ }
31
+
24
32
  const oldConfig = deepClone(helper.options)
25
33
  try {
26
34
  helper._setConfig(deepMerge(deepClone(oldConfig), config))
@@ -41,7 +49,7 @@ export default function () {
41
49
  for (let name in context.config) {
42
50
  const config = context.config[name]
43
51
  if (name === '0') {
44
- // first helper
52
+ // first helper - get dynamically
45
53
  name = Object.keys(helpers)[0]
46
54
  }
47
55
  const helper = helpers[name]
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeceptjs",
3
- "version": "4.0.1-beta.3",
3
+ "version": "4.0.1-beta.5",
4
4
  "type": "module",
5
5
  "description": "Supercharged End 2 End Testing Framework for NodeJS",
6
6
  "keywords": [