codeceptjs 3.7.5-beta.7 → 3.7.5-beta.9

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.
package/lib/mocha/test.js CHANGED
@@ -121,6 +121,7 @@ function serializeTest(test, error = null) {
121
121
  }
122
122
 
123
123
  return {
124
+ file: test.file ? relativeDir(test.file) : undefined,
124
125
  opts: test.opts || {},
125
126
  tags: test.tags || [],
126
127
  uid: test.uid,
@@ -41,72 +41,77 @@ module.exports = function (config) {
41
41
 
42
42
  // Track test failures - only when not using workers
43
43
  event.dispatcher.on(event.test.failed, test => {
44
- // Skip if main process is using workers (will collect from consolidated results)
45
- if (store.hasWorkers) {
46
- return
47
- }
48
-
49
- // Skip if we're in a worker thread (CodeceptJS uses worker_threads)
44
+ // Skip collection in worker threads to avoid duplicates
50
45
  try {
51
46
  const { isMainThread } = require('worker_threads')
52
- if (!isMainThread) {
53
- return
54
- }
47
+ if (!isMainThread) return
55
48
  } catch (e) {
56
- // worker_threads not available, assume main thread
49
+ // worker_threads not available, continue
57
50
  }
58
51
 
59
- allTestsPassed = false
52
+ if (store.hasWorkers) return // Skip if running with workers
60
53
 
61
- const failedTest = {
62
- title: test.title,
63
- fullTitle: test.fullTitle(),
64
- file: test.file || (test.parent && test.parent.file),
65
- uid: test.uid,
66
- timestamp: new Date().toISOString(),
67
- }
54
+ // Only collect on final failure (when retries are exhausted or no retries configured)
55
+ const currentRetry = test._currentRetry || 0
56
+ const maxRetries = typeof test.retries === 'function' ? test.retries() : (test.retries || 0)
57
+
58
+ // Only add to failed tests if this is the final attempt
59
+ if (currentRetry >= maxRetries) {
60
+ allTestsPassed = false
61
+
62
+ const failedTest = {
63
+ title: test.title,
64
+ fullTitle: test.fullTitle(),
65
+ file: test.file || (test.parent && test.parent.file),
66
+ uid: test.uid,
67
+ timestamp: new Date().toISOString(),
68
+ }
68
69
 
69
- // Add parent suite information
70
- if (test.parent) {
71
- failedTest.suite = test.parent.title
72
- failedTest.suiteFile = test.parent.file
73
- }
70
+ // Add parent suite information
71
+ if (test.parent) {
72
+ failedTest.suite = test.parent.title
73
+ failedTest.suiteFile = test.parent.file
74
+ }
74
75
 
75
- // Add error information if available
76
- if (test.err && options.includeStackTrace) {
77
- failedTest.error = {
78
- message: test.err.message || 'Test failed',
79
- stack: test.err.stack || '',
80
- name: test.err.name || 'Error',
76
+ // Add error information if available
77
+ if (test.err && options.includeStackTrace) {
78
+ failedTest.error = {
79
+ message: test.err.message || 'Test failed',
80
+ stack: test.err.stack || '',
81
+ name: test.err.name || 'Error',
82
+ }
81
83
  }
82
- }
83
84
 
84
- // Add metadata if available
85
- if (options.includeMetadata) {
86
- failedTest.metadata = {
87
- tags: test.tags || [],
88
- meta: test.meta || {},
89
- opts: test.opts || {},
90
- duration: test.duration || 0,
91
- retries: test.retries || 0,
85
+ // Add metadata if available
86
+ if (options.includeMetadata) {
87
+ failedTest.metadata = {
88
+ tags: test.tags || [],
89
+ meta: test.meta || {},
90
+ opts: test.opts || {},
91
+ duration: test.duration || 0,
92
+ // Only include retries if it represents actual retry attempts, not the config value
93
+ ...(test._currentRetry > 0 && { actualRetries: test._currentRetry }),
94
+ ...(maxRetries > 0 && maxRetries !== -1 && { maxRetries: maxRetries }),
95
+ }
92
96
  }
93
- }
94
97
 
95
- // Add BDD/Gherkin information if available
96
- if (test.parent && test.parent.feature) {
97
- failedTest.bdd = {
98
- feature: test.parent.feature.name || test.parent.title,
99
- scenario: test.title,
100
- featureFile: test.parent.file,
98
+ // Add BDD/Gherkin information if available
99
+ if (test.parent && test.parent.feature) {
100
+ failedTest.bdd = {
101
+ feature: test.parent.feature.name || test.parent.title,
102
+ scenario: test.title,
103
+ featureFile: test.parent.file,
104
+ }
101
105
  }
102
- }
103
106
 
104
- failedTests.push(failedTest)
105
- output.print(`Failed Tests Tracker: Recorded failed test - ${test.title}`)
107
+ failedTests.push(failedTest)
108
+ output.print(`Failed Tests Tracker: Recorded failed test - ${test.title}`)
109
+ }
106
110
  })
107
111
 
108
112
  // Handle test completion and save failed tests
109
113
  event.dispatcher.on(event.all.result, (result) => {
114
+
110
115
  // Respect CodeceptJS output directory like other plugins
111
116
  const outputDir = global.output_dir || './output'
112
117
  const outputPath = path.isAbsolute(options.outputFile)
@@ -114,14 +119,27 @@ module.exports = function (config) {
114
119
  : path.resolve(outputDir, options.outputFile)
115
120
  let allFailedTests = [...failedTests]
116
121
 
117
- // In worker mode, collect failed tests from consolidated result
118
- if (store.hasWorkers && result && result.tests) {
119
- const workerFailedTests = result.tests.filter(test => test.state === 'failed' || test.err)
122
+ // Collect failed tests from result (both worker and single-process modes)
123
+ if (result) {
124
+ let resultFailedTests = []
125
+
126
+ // Worker mode: result.tests
127
+ if (store.hasWorkers && result.tests) {
128
+ resultFailedTests = result.tests.filter(test => test.state === 'failed' || test.err)
129
+ }
130
+ // Single-process mode: result._failures or result._tests
131
+ else if (!store.hasWorkers && (result._failures || result._tests)) {
132
+ if (result._failures && result._failures.length > 0) {
133
+ resultFailedTests = result._failures.map(failure => failure.test || failure)
134
+ } else if (result._tests) {
135
+ resultFailedTests = result._tests.filter(test => test.state === 'failed' || test.err)
136
+ }
137
+ }
120
138
 
121
139
  // Use a Set to track unique test identifiers to prevent duplicates
122
140
  const existingTestIds = new Set(allFailedTests.map(test => test.uid || `${test.file}:${test.title}`))
123
141
 
124
- workerFailedTests.forEach(test => {
142
+ resultFailedTests.forEach(test => {
125
143
  // Create unique identifier for deduplication
126
144
  const testId = test.uid || `${test.file || 'unknown'}:${test.title}`
127
145
 
@@ -177,7 +195,7 @@ module.exports = function (config) {
177
195
  existingTestIds.add(testId)
178
196
  })
179
197
 
180
- output.print(`Failed Tests Tracker: Collected ${workerFailedTests.length} failed tests from workers`)
198
+ output.print(`Failed Tests Tracker: Collected ${resultFailedTests.length} failed tests from result`)
181
199
  }
182
200
 
183
201
  if (allFailedTests.length === 0) {
@@ -242,12 +260,22 @@ module.exports = function (config) {
242
260
 
243
261
  // If still unknown, try to extract from error stack trace
244
262
  if (filePath === 'unknown' && test.err && test.err.stack) {
245
- const stackMatch = test.err.stack.match(/at.*\(([^)]+\.js):\d+:\d+\)/)
246
- if (stackMatch && stackMatch[1]) {
247
- // Convert absolute path to relative path
248
- const absolutePath = stackMatch[1]
249
- const relativePath = absolutePath.replace(process.cwd() + '/', '')
250
- filePath = relativePath
263
+ // Try multiple regex patterns for different stack trace formats
264
+ const patterns = [
265
+ /at.*\(([^)]+\.js):\d+:\d+\)/, // Standard format
266
+ /at.*\(.*[\/\\]([^\/\\]+\.js):\d+:\d+\)/, // With path separators
267
+ /\(([^)]*\.js):\d+:\d+\)/, // Simpler format
268
+ /([^\/\\]+\.js):\d+:\d+/, // Just filename with line numbers
269
+ ]
270
+
271
+ for (const pattern of patterns) {
272
+ const stackMatch = test.err.stack.match(pattern)
273
+ if (stackMatch && stackMatch[1]) {
274
+ const absolutePath = stackMatch[1]
275
+ const relativePath = absolutePath.replace(process.cwd() + '/', '').replace(/^.*[\/\\]/, '')
276
+ filePath = relativePath
277
+ break
278
+ }
251
279
  }
252
280
  }
253
281
 
@@ -308,7 +336,7 @@ module.exports = function (config) {
308
336
  allFailedTests.push(failedTest)
309
337
  })
310
338
 
311
- output.print(`Failed Tests Tracker: Collected ${workerFailedTests.length} failed tests from workers`)
339
+ output.print(`Failed Tests Tracker: Collected ${allFailedTests.length - failedTests.length} failed tests from workers`)
312
340
  }
313
341
 
314
342
  if (allFailedTests.length === 0) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "codeceptjs",
3
- "version": "3.7.5-beta.7",
3
+ "version": "3.7.5-beta.9",
4
4
  "description": "Supercharged End 2 End Testing Framework for NodeJS",
5
5
  "keywords": [
6
6
  "acceptance",