codeceptjs 4.0.2-beta.16 → 4.0.2-beta.18
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/command/workers/runTests.js +3 -43
- package/lib/utils/typescript.js +43 -3
- package/lib/workers.js +0 -10
- package/package.json +1 -1
|
@@ -120,14 +120,12 @@ let config
|
|
|
120
120
|
initPromise = (async function () {
|
|
121
121
|
try {
|
|
122
122
|
// Add staggered delay at the very start to prevent resource conflicts
|
|
123
|
-
|
|
123
|
+
// Longer delay for browser initialization conflicts
|
|
124
|
+
const delay = (workerIndex - 1) * 2000 // 0ms, 2s, 4s, etc.
|
|
124
125
|
if (delay > 0) {
|
|
125
|
-
console.log(`[Worker ${workerIndex}] Waiting ${delay}ms to stagger initialization...`)
|
|
126
126
|
await new Promise(resolve => setTimeout(resolve, delay))
|
|
127
127
|
}
|
|
128
128
|
|
|
129
|
-
console.log(`[Worker ${workerIndex}] Starting initialization...`)
|
|
130
|
-
|
|
131
129
|
// Import modules dynamically to avoid ES Module loader race conditions in Node 22.x
|
|
132
130
|
const eventModule = await import('../../event.js')
|
|
133
131
|
const containerModule = await import('../../container.js')
|
|
@@ -135,8 +133,6 @@ initPromise = (async function () {
|
|
|
135
133
|
const coreUtilsModule = await import('../../utils.js')
|
|
136
134
|
const CodeceptModule = await import('../../codecept.js')
|
|
137
135
|
|
|
138
|
-
console.log(`[Worker ${workerIndex}] Modules imported`)
|
|
139
|
-
|
|
140
136
|
event = eventModule.default
|
|
141
137
|
container = containerModule.default
|
|
142
138
|
getConfig = utilsModule.getConfig
|
|
@@ -146,23 +142,17 @@ initPromise = (async function () {
|
|
|
146
142
|
|
|
147
143
|
const overrideConfigs = tryOrDefault(() => JSON.parse(options.override), {})
|
|
148
144
|
|
|
149
|
-
console.log(`[Worker ${workerIndex}] Loading config...`)
|
|
150
|
-
|
|
151
145
|
let baseConfig
|
|
152
146
|
try {
|
|
153
147
|
// IMPORTANT: await is required here since getConfig is async
|
|
154
148
|
baseConfig = await getConfig(options.config || testRoot)
|
|
155
|
-
console.log(`[Worker ${workerIndex}] Config loaded successfully`)
|
|
156
149
|
} catch (configErr) {
|
|
157
150
|
process.stderr.write(`[Worker ${workerIndex}] FAILED loading config: ${configErr.message}\n`)
|
|
158
151
|
process.stderr.write(`${configErr.stack}\n`)
|
|
159
|
-
// Ensure error is written before exit
|
|
160
152
|
await new Promise(resolve => setTimeout(resolve, 100))
|
|
161
153
|
process.exit(1)
|
|
162
154
|
}
|
|
163
155
|
|
|
164
|
-
console.log(`[Worker ${workerIndex}] Config loaded, creating Codecept...`)
|
|
165
|
-
|
|
166
156
|
// important deep merge so dynamic things e.g. functions on config are not overridden
|
|
167
157
|
config = deepMerge(baseConfig, overrideConfigs)
|
|
168
158
|
|
|
@@ -170,17 +160,14 @@ initPromise = (async function () {
|
|
|
170
160
|
const optsWithChild = { ...options, child: workerIndex }
|
|
171
161
|
codecept = new Codecept(config, optsWithChild)
|
|
172
162
|
|
|
173
|
-
console.log(`[Worker ${workerIndex}] Initializing Codecept...`)
|
|
174
163
|
try {
|
|
175
164
|
await codecept.init(testRoot)
|
|
176
|
-
console.log(`[Worker ${workerIndex}] Codecept initialized successfully`)
|
|
177
165
|
} catch (initErr) {
|
|
178
166
|
process.stderr.write(`[Worker ${workerIndex}] FAILED during codecept.init(): ${initErr.message}\n`)
|
|
179
167
|
process.stderr.write(`${initErr.stack}\n`)
|
|
180
168
|
process.exit(1)
|
|
181
169
|
}
|
|
182
170
|
|
|
183
|
-
console.log(`[Worker ${workerIndex}] Loading tests...`)
|
|
184
171
|
codecept.loadTests()
|
|
185
172
|
mocha = container.mocha()
|
|
186
173
|
|
|
@@ -189,14 +176,9 @@ initPromise = (async function () {
|
|
|
189
176
|
// We'll reload test files fresh for each test request
|
|
190
177
|
} else {
|
|
191
178
|
// Legacy mode - filter tests upfront
|
|
192
|
-
console.log(`[Worker ${workerIndex}] Starting test filtering. Assigned ${tests.length} test UIDs`)
|
|
193
179
|
filterTests()
|
|
194
|
-
const finalCount = mocha.suite.total()
|
|
195
|
-
console.log(`[Worker ${workerIndex}] After filtering: ${finalCount} tests to run`)
|
|
196
180
|
}
|
|
197
181
|
|
|
198
|
-
console.log(`[Worker ${workerIndex}] Initialization complete, starting tests...`)
|
|
199
|
-
|
|
200
182
|
// run tests
|
|
201
183
|
if (poolMode) {
|
|
202
184
|
await runPoolTests()
|
|
@@ -220,7 +202,6 @@ async function runTests() {
|
|
|
220
202
|
try {
|
|
221
203
|
await codecept.bootstrap()
|
|
222
204
|
} catch (err) {
|
|
223
|
-
console.error(`[Worker ${workerIndex}] Bootstrap error:`, err.message)
|
|
224
205
|
throw new Error(`Error while running bootstrap file :${err}`)
|
|
225
206
|
}
|
|
226
207
|
listenToParentThread()
|
|
@@ -229,13 +210,12 @@ async function runTests() {
|
|
|
229
210
|
try {
|
|
230
211
|
await codecept.run()
|
|
231
212
|
} catch (err) {
|
|
232
|
-
console.error(`[Worker ${workerIndex}] Runtime error:`, err.message)
|
|
233
213
|
throw err
|
|
234
214
|
} finally {
|
|
235
215
|
try {
|
|
236
216
|
await codecept.teardown()
|
|
237
217
|
} catch (err) {
|
|
238
|
-
|
|
218
|
+
// Ignore teardown errors
|
|
239
219
|
}
|
|
240
220
|
}
|
|
241
221
|
}
|
|
@@ -424,26 +404,6 @@ function filterTests() {
|
|
|
424
404
|
mocha.files = files
|
|
425
405
|
mocha.loadFiles()
|
|
426
406
|
|
|
427
|
-
// Collect all loaded tests for debugging
|
|
428
|
-
const allLoadedTests = [];
|
|
429
|
-
mocha.suite.eachTest(test => {
|
|
430
|
-
if (test) {
|
|
431
|
-
allLoadedTests.push({ uid: test.uid, title: test.fullTitle() });
|
|
432
|
-
}
|
|
433
|
-
});
|
|
434
|
-
|
|
435
|
-
console.log(`[Worker ${workerIndex}] Loaded ${allLoadedTests.length} tests from ${files.length} files`);
|
|
436
|
-
console.log(`[Worker ${workerIndex}] Expecting ${tests.length} test UIDs`);
|
|
437
|
-
|
|
438
|
-
const loadedUids = new Set(allLoadedTests.map(t => t.uid));
|
|
439
|
-
const missingTests = tests.filter(uid => !loadedUids.has(uid));
|
|
440
|
-
|
|
441
|
-
if (missingTests.length > 0) {
|
|
442
|
-
console.error(`[Worker ${workerIndex}] ERROR: ${missingTests.length} assigned tests NOT FOUND in loaded files!`);
|
|
443
|
-
console.error(`[Worker ${workerIndex}] Missing UIDs:`, missingTests);
|
|
444
|
-
console.error(`[Worker ${workerIndex}] Available UIDs:`, Array.from(loadedUids).slice(0, 5), '...');
|
|
445
|
-
}
|
|
446
|
-
|
|
447
407
|
// Recursively filter tests in all suites (including nested ones)
|
|
448
408
|
const filterSuiteTests = (suite) => {
|
|
449
409
|
suite.tests = suite.tests.filter(test => tests.indexOf(test.uid) >= 0)
|
package/lib/utils/typescript.js
CHANGED
|
@@ -118,20 +118,25 @@ const __dirname = __dirname_fn(__filename);
|
|
|
118
118
|
// Transpile this file
|
|
119
119
|
let jsContent = transpileTS(filePath)
|
|
120
120
|
|
|
121
|
-
// Find all relative TypeScript imports in this file
|
|
121
|
+
// Find all relative TypeScript imports in this file (both ESM imports and require() calls)
|
|
122
122
|
const importRegex = /from\s+['"](\.[^'"]+?)(?:\.ts)?['"]/g
|
|
123
|
+
const requireRegex = /require\s*\(\s*['"](\.[^'"]+?)(?:\.ts)?['"]\s*\)/g
|
|
123
124
|
let match
|
|
124
125
|
const imports = []
|
|
125
126
|
|
|
126
127
|
while ((match = importRegex.exec(jsContent)) !== null) {
|
|
127
|
-
imports.push(match[1])
|
|
128
|
+
imports.push({ path: match[1], type: 'import' })
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
while ((match = requireRegex.exec(jsContent)) !== null) {
|
|
132
|
+
imports.push({ path: match[1], type: 'require' })
|
|
128
133
|
}
|
|
129
134
|
|
|
130
135
|
// Get the base directory for this file
|
|
131
136
|
const fileBaseDir = path.dirname(filePath)
|
|
132
137
|
|
|
133
138
|
// Recursively transpile each imported TypeScript file
|
|
134
|
-
for (const relativeImport of imports) {
|
|
139
|
+
for (const { path: relativeImport } of imports) {
|
|
135
140
|
let importedPath = path.resolve(fileBaseDir, relativeImport)
|
|
136
141
|
|
|
137
142
|
// Handle .js extensions that might actually be .ts files
|
|
@@ -222,6 +227,41 @@ const __dirname = __dirname_fn(__filename);
|
|
|
222
227
|
}
|
|
223
228
|
)
|
|
224
229
|
|
|
230
|
+
// Also rewrite require() calls to point to transpiled TypeScript files
|
|
231
|
+
jsContent = jsContent.replace(
|
|
232
|
+
/require\s*\(\s*['"](\.[^'"]+?)(?:\.ts)?['"]\s*\)/g,
|
|
233
|
+
(match, requirePath) => {
|
|
234
|
+
let resolvedPath = path.resolve(fileBaseDir, requirePath)
|
|
235
|
+
const originalExt = path.extname(requirePath)
|
|
236
|
+
|
|
237
|
+
// Handle .js extension that might be .ts
|
|
238
|
+
if (resolvedPath.endsWith('.js')) {
|
|
239
|
+
const tsVersion = resolvedPath.replace(/\.js$/, '.ts')
|
|
240
|
+
if (transpiledFiles.has(tsVersion)) {
|
|
241
|
+
const tempFile = transpiledFiles.get(tsVersion)
|
|
242
|
+
const relPath = path.relative(fileBaseDir, tempFile).replace(/\\/g, '/')
|
|
243
|
+
const finalPath = relPath.startsWith('.') ? relPath : './' + relPath
|
|
244
|
+
return `require('${finalPath}')`
|
|
245
|
+
}
|
|
246
|
+
return match
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
// Try with .ts extension
|
|
250
|
+
const tsPath = resolvedPath.endsWith('.ts') ? resolvedPath : resolvedPath + '.ts'
|
|
251
|
+
|
|
252
|
+
// If we transpiled this file, use the temp file
|
|
253
|
+
if (transpiledFiles.has(tsPath)) {
|
|
254
|
+
const tempFile = transpiledFiles.get(tsPath)
|
|
255
|
+
const relPath = path.relative(fileBaseDir, tempFile).replace(/\\/g, '/')
|
|
256
|
+
const finalPath = relPath.startsWith('.') ? relPath : './' + relPath
|
|
257
|
+
return `require('${finalPath}')`
|
|
258
|
+
}
|
|
259
|
+
|
|
260
|
+
// Otherwise, keep the require as-is
|
|
261
|
+
return match
|
|
262
|
+
}
|
|
263
|
+
)
|
|
264
|
+
|
|
225
265
|
// Write the transpiled file with updated imports
|
|
226
266
|
const tempFile = filePath.replace(/\.ts$/, '.temp.mjs')
|
|
227
267
|
fs.writeFileSync(tempFile, jsContent)
|
package/lib/workers.js
CHANGED
|
@@ -582,11 +582,6 @@ class Workers extends EventEmitter {
|
|
|
582
582
|
// Track current test
|
|
583
583
|
if (message.event === event.test.started && message.data) {
|
|
584
584
|
currentTest = message.data.title || message.data.fullTitle
|
|
585
|
-
console.log(`[Worker ${message.workerIndex}] Started: ${currentTest}`)
|
|
586
|
-
}
|
|
587
|
-
|
|
588
|
-
if (message.event === event.test.finished && message.data) {
|
|
589
|
-
console.log(`[Worker ${message.workerIndex}] Finished: ${message.data.title || currentTest}`)
|
|
590
585
|
}
|
|
591
586
|
|
|
592
587
|
output.process(message.workerIndex)
|
|
@@ -724,8 +719,6 @@ class Workers extends EventEmitter {
|
|
|
724
719
|
// Mark as failed
|
|
725
720
|
process.exitCode = 1
|
|
726
721
|
}
|
|
727
|
-
|
|
728
|
-
console.log(`[Main] Workers closed: ${this.closedWorkers}/${this.numberOfWorkers}`)
|
|
729
722
|
|
|
730
723
|
if (this.isPoolMode) {
|
|
731
724
|
// Pool mode: finish when all workers have exited and no more tests
|
|
@@ -740,7 +733,6 @@ class Workers extends EventEmitter {
|
|
|
740
733
|
}
|
|
741
734
|
|
|
742
735
|
_finishRun() {
|
|
743
|
-
console.log('[Main] Finishing test run...')
|
|
744
736
|
event.dispatcher.emit(event.workers.after, { tests: this.workers.map(worker => worker.tests) })
|
|
745
737
|
if (Container.result().hasFailed || this.errors.length > 0) {
|
|
746
738
|
process.exitCode = 1
|
|
@@ -782,10 +774,8 @@ class Workers extends EventEmitter {
|
|
|
782
774
|
this._testStates.clear()
|
|
783
775
|
}
|
|
784
776
|
|
|
785
|
-
console.log('[Main] Emitting final results...')
|
|
786
777
|
this.emit(event.all.result, Container.result())
|
|
787
778
|
event.dispatcher.emit(event.workers.result, Container.result())
|
|
788
|
-
console.log('[Main] Emitting end event...')
|
|
789
779
|
this.emit('end') // internal event
|
|
790
780
|
}
|
|
791
781
|
|