Skip to content

Commit f7bc6f5

Browse files
committed
fix workers again
1 parent a3bde03 commit f7bc6f5

File tree

14 files changed

+96
-100
lines changed

14 files changed

+96
-100
lines changed

lib/codecept.js

Lines changed: 20 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -120,23 +120,26 @@ class Codecept {
120120
* Executes hooks.
121121
*/
122122
async runHooks() {
123-
// default hooks - dynamic imports for ESM
124-
const listenerModules = [
125-
'./listener/store.js',
126-
'./listener/steps.js',
127-
'./listener/config.js',
128-
'./listener/result.js',
129-
'./listener/helpers.js',
130-
'./listener/globalTimeout.js',
131-
'./listener/globalRetry.js',
132-
'./listener/retryEnhancer.js',
133-
'./listener/exit.js',
134-
'./listener/emptyRun.js',
135-
]
136-
137-
for (const modulePath of listenerModules) {
138-
const module = await import(modulePath)
139-
runHook(module.default || module)
123+
// For workers parent process we only need plugins/hooks.
124+
// Core listeners are executed inside worker threads.
125+
if (!this.opts?.skipDefaultListeners) {
126+
const listenerModules = [
127+
'./listener/store.js',
128+
'./listener/steps.js',
129+
'./listener/config.js',
130+
'./listener/result.js',
131+
'./listener/helpers.js',
132+
'./listener/globalTimeout.js',
133+
'./listener/globalRetry.js',
134+
'./listener/retryEnhancer.js',
135+
'./listener/exit.js',
136+
'./listener/emptyRun.js',
137+
]
138+
139+
for (const modulePath of listenerModules) {
140+
const module = await import(modulePath)
141+
runHook(module.default || module)
142+
}
140143
}
141144

142145
// custom hooks (previous iteration of plugins)

lib/command/run-workers.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@ export default async function (workerCount, selectedRuns, options) {
4141
output.print(`CodeceptJS v${Codecept.version()} ${output.standWithUkraine()}`)
4242
output.print(`Running tests in ${output.styles.bold(numberOfWorkers)} workers...`)
4343
store.hasWorkers = true
44+
process.env.RUNS_WITH_WORKERS = 'true'
4445

4546
const workers = new Workers(numberOfWorkers, config)
4647
workers.overrideConfig(overrideConfigs)

lib/command/workers/runTests.js

Lines changed: 3 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -212,36 +212,10 @@ initPromise = (async function () {
212212
await runPoolTests()
213213
} else if (mocha.suite.total()) {
214214
await runTests()
215-
await new Promise(resolve => setTimeout(resolve, 100))
216-
// Remove message listener before closing to prevent event loop hanging
217-
if (global.parentMessageHandler) {
218-
try {
219-
parentPort?.off('message', global.parentMessageHandler)
220-
} catch (err) {
221-
// Ignore errors when removing listener
222-
}
223-
}
224-
try {
225-
parentPort?.close()
226-
} catch (err) {
227-
// Ignore errors when closing port
228-
}
229215
} else {
230216
// No tests to run, close the worker
231217
console.error(`[Worker ${workerIndex}] ERROR: No tests found after filtering! Assigned ${tests.length} UIDs but none matched.`)
232-
// Remove message listener before closing to prevent event loop hanging
233-
if (global.parentMessageHandler) {
234-
try {
235-
parentPort?.off('message', global.parentMessageHandler)
236-
} catch (err) {
237-
// Ignore errors when removing listener
238-
}
239-
}
240-
try {
241-
parentPort?.close()
242-
} catch (err) {
243-
// Ignore errors when closing port
244-
}
218+
parentPort?.close()
245219
}
246220
} catch (err) {
247221
if (global.container?.tsFileMapping && fixErrorStack) {
@@ -584,11 +558,9 @@ function sendToParentThread(data) {
584558

585559
function listenToParentThread() {
586560
if (!poolMode) {
587-
const messageHandler = eventData => {
561+
parentPort?.on('message', eventData => {
588562
container.append({ support: eventData.data })
589-
}
590-
parentPort?.on('message', messageHandler)
591-
global.parentMessageHandler = messageHandler
563+
})
592564
}
593565
// In pool mode, message handling is done in runPoolTests()
594566
}

lib/container.js

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -657,13 +657,28 @@ async function createPlugins(config, options = {}) {
657657
const enabledPluginsByOptions = (options.plugins || '').split(',')
658658
for (const pluginName in config) {
659659
if (!config[pluginName]) config[pluginName] = {}
660-
if (!config[pluginName].enabled && enabledPluginsByOptions.indexOf(pluginName) < 0) {
660+
const pluginConfig = config[pluginName]
661+
if (!pluginConfig.enabled && enabledPluginsByOptions.indexOf(pluginName) < 0) {
661662
continue // plugin is disabled
662663
}
664+
665+
// Generic workers gate:
666+
// - runInWorker / runInWorkers controls plugin execution inside worker threads.
667+
// - runInParent / runInMain can disable plugin in workers parent process.
668+
const runInWorker = pluginConfig.runInWorker ?? pluginConfig.runInWorkers ?? (pluginName === 'testomatio' ? false : true)
669+
const runInParent = pluginConfig.runInParent ?? pluginConfig.runInMain ?? true
670+
671+
if (options.child && !runInWorker) {
672+
continue
673+
}
674+
675+
if (!options.child && process.env.RUNS_WITH_WORKERS === 'true' && !runInParent) {
676+
continue
677+
}
663678
let module
664679
try {
665-
if (config[pluginName].require) {
666-
module = config[pluginName].require
680+
if (pluginConfig.require) {
681+
module = pluginConfig.require
667682
if (module.startsWith('.')) {
668683
// local
669684
module = path.resolve(global.codecept_dir, module) // custom plugin
@@ -673,15 +688,7 @@ async function createPlugins(config, options = {}) {
673688
}
674689

675690
// Use async loading for all plugins (ESM and CJS)
676-
plugins[pluginName] = await loadPluginAsync(module, config[pluginName])
677-
678-
// Skip loading plugin in parent process if runInParent is false
679-
if (config[pluginName].runInParent === false && process.env.RUNS_WITH_WORKERS) {
680-
delete plugins[pluginName]
681-
debug(`plugin ${pluginName} skipped in parent process (runInParent: false)`)
682-
continue
683-
}
684-
691+
plugins[pluginName] = await loadPluginAsync(module, pluginConfig)
685692
debug(`plugin ${pluginName} loaded via async import`)
686693
} catch (err) {
687694
throw new Error(`Could not load plugin ${pluginName} from module '${module}':\n${err.message}\n${err.stack}`)

lib/listener/globalTimeout.js

Lines changed: 5 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ import debugModule from 'debug'
77
const debug = debugModule('codeceptjs:timeout')
88
import { TIMEOUT_ORDER, TimeoutError, TestTimeoutError, StepTimeoutError } from '../timeout.js'
99
import { BeforeSuiteHook, AfterSuiteHook } from '../mocha/hooks.js'
10-
import { extractStepCode } from '../step.js'
1110

1211
export default function () {
1312
let timeout
@@ -123,15 +122,15 @@ export default function () {
123122
if (typeof timeout !== 'number') return
124123

125124
if (!store.timeouts) {
126-
debug('step', extractStepCode(step), 'timeout disabled')
125+
debug('step', step.toCode().trim(), 'timeout disabled')
127126
return
128127
}
129128

130129
if (timeout < 0) {
131130
debug('Previous steps timed out, setting timeout to 0.01s')
132131
step.setTimeout(0.01, TIMEOUT_ORDER.testOrSuite)
133132
} else {
134-
debug(`Setting timeout ${timeout}ms for step ${extractStepCode(step)}`)
133+
debug(`Setting timeout ${timeout}ms for step ${step.toCode().trim()}`)
135134
step.setTimeout(timeout, TIMEOUT_ORDER.testOrSuite)
136135
}
137136
})
@@ -159,17 +158,17 @@ export default function () {
159158

160159
event.dispatcher.on(event.step.finished, step => {
161160
if (!store.timeouts) {
162-
debug('step', extractStepCode(step), 'timeout disabled')
161+
debug('step', step.toCode().trim(), 'timeout disabled')
163162
return
164163
}
165164

166165
if (typeof timeout === 'number') debug('Timeout', timeout)
167166

168-
debug(`step ${extractStepCode(step)}:${step.status} duration`, step.duration)
167+
debug(`step ${step.toCode().trim()}:${step.status} duration`, step.duration)
169168
if (typeof timeout === 'number' && !Number.isNaN(timeout)) timeout -= step.duration
170169

171170
if (typeof timeout === 'number' && timeout <= 0 && recorder.isRunning()) {
172-
debug(`step ${extractStepCode(step)} timed out`)
171+
debug(`step ${step.toCode().trim()} timed out`)
173172
recorder.throw(new TestTimeoutError(currentTimeout))
174173
}
175174
})

lib/plugin/autoDelay.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,6 @@ const defaultConfig = {
1515
methods: methodsToDelay,
1616
delayBefore: 100,
1717
delayAfter: 200,
18-
runInParent: false,
1918
}
2019

2120
/**

lib/plugin/pauseOnFail.js

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -22,11 +22,7 @@ import pause from '../pause.js'
2222
* ```
2323
*
2424
*/
25-
const defaultConfig = {
26-
runInParent: false,
27-
}
28-
29-
export default function(config) {
25+
export default function() {
3026
let failed = false
3127

3228
event.dispatcher.on(event.test.started, () => {

lib/plugin/retryFailedStep.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@ const defaultConfig = {
77
defaultIgnoredSteps: ['amOnPage', 'wait*', 'send*', 'execute*', 'run*', 'have*'],
88
factor: 1.5,
99
ignoredSteps: [],
10-
runInParent: false,
1110
deferToScenarioRetries: true,
1211
}
1312

lib/plugin/screenshotOnFail.js

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,6 @@ const defaultConfig = {
1717
uniqueScreenshotNames: false,
1818
disableScreenshots: false,
1919
fullPageScreenshots: false,
20-
runInParent: false,
2120
}
2221

2322
const supportedHelpers = Container.STANDARD_ACTING_HELPERS

lib/step.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
*/
66
import BaseStep from './step/base.js'
77
import StepConfig from './step/config.js'
8-
import Step, { extractStepCode } from './step/helper.js'
8+
import Step from './step/helper.js'
99

1010
/**
1111
* MetaStep is a step that is used to wrap other steps.
@@ -20,4 +20,4 @@ import MetaStep from './step/meta.js'
2020
import FuncStep from './step/func.js'
2121

2222
export default Step
23-
export { MetaStep, BaseStep, StepConfig, FuncStep, extractStepCode }
23+
export { MetaStep, BaseStep, StepConfig, FuncStep }

0 commit comments

Comments
 (0)