Skip to content

Commit 16b2f32

Browse files
miraoclaude
andauthored
fix(run-multiple): restore plugin loading and per-child reportDir (#5577) (#5578)
Two regressions introduced during the 3.x → 4.x ESM migration: ## Bug 1 – plugins with runInWorker:false silently skipped in child processes lib/container.js used options.child to detect "running inside a worker thread" and skipped plugins whose runInWorker is false (testomatio defaults to false). But run-multiple also sets --child on every forked child process, so those plugins were incorrectly skipped there too. Fix: replace options.child with !isMainThread (worker_threads). A run-multiple child is a freshly-forked OS process whose isMainThread is true, so the gate no longer fires. An actual run-workers worker thread has isMainThread === false, so the gate still fires as intended. | Context | options.child | isMainThread | before (skipped?) | after | |---------------------------|---------------|--------------|-------------------|--------| | run-workers worker thread | truthy (idx) | false | skipped ✓ | skipped ✓ | | run-multiple child proc | truthy (str) | true | skipped ✗ (bug) | loads ✓ | | normal run / parent proc | falsy | true | loads ✓ | loads ✓ | ## Bug 2 – all children write to the same reportDir, last one wins 3.x run-multiple.js replaced three per-child directory keys before forking: output, reportDir, mochaFile The 4.x port dropped the reportDir line, so every child kept the shared reportDir value from the config (e.g. "output/report") and overwrote each other's HTML file. Fix: restore the missing replaceValueDeep('reportDir', ...) call so each child receives its own directory, matching 3.x behaviour. Regression test added: verifies that a plugin with runInWorker:false is initialised once per child and that each child receives a distinct reportDir. Co-authored-by: Claude Sonnet 4.6 <noreply@anthropic.com>
1 parent 2c89828 commit 16b2f32

5 files changed

Lines changed: 55 additions & 2 deletions

File tree

lib/command/run-multiple.js

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -140,6 +140,7 @@ function executeRun(runName, runConfig) {
140140

141141
// tweaking default output directories
142142
overriddenConfig = replaceValueDeep(overriddenConfig, 'output', path.join(config.output, outputDir))
143+
overriddenConfig = replaceValueDeep(overriddenConfig, 'reportDir', path.join(config.output, outputDir))
143144
overriddenConfig = replaceValueDeep(overriddenConfig, 'mochaFile', path.join(config.output, outputDir, `${browserName}_report.xml`))
144145

145146
// override tests configuration

lib/container.js

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { globSync } from 'glob'
22
import path from 'path'
33
import fs from 'fs'
4+
import { isMainThread } from 'worker_threads'
45
import debugModule from 'debug'
56
const debug = debugModule('codeceptjs:container')
67
import { MetaStep } from './step.js'
@@ -731,11 +732,11 @@ async function createPlugins(config, options = {}) {
731732
const runInWorker = pluginConfig.runInWorker ?? pluginConfig.runInWorkers ?? (pluginName === 'testomatio' ? false : true)
732733
const runInParent = pluginConfig.runInParent ?? pluginConfig.runInMain ?? true
733734

734-
if (options.child && !runInWorker) {
735+
if (!isMainThread && !runInWorker) {
735736
continue
736737
}
737738

738-
if (!options.child && store.workerMode && !runInParent) {
739+
if (isMainThread && store.workerMode && !runInParent) {
739740
continue
740741
}
741742
let module
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
export const config = {
2+
tests: './*_test.multiple.js',
3+
timeout: 10000,
4+
output: './output',
5+
helpers: {
6+
FakeDriver: {
7+
require: '../fake_driver',
8+
browser: 'dummy',
9+
windowSize: 'maximize',
10+
},
11+
},
12+
multiple: {
13+
default: {
14+
browsers: ['chrome', 'firefox'],
15+
},
16+
},
17+
plugins: {
18+
runInWorkerFalsePlugin: {
19+
enabled: true,
20+
runInWorker: false,
21+
require: './plugin-runInWorkerFalse.js',
22+
reportDir: 'output/report',
23+
},
24+
},
25+
bootstrap: false,
26+
mocha: {},
27+
name: 'sandbox',
28+
}
Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export default function (config) {
2+
process.stdout.write('plugin-runInWorkerFalse:loaded\n')
3+
if (config.reportDir) {
4+
process.stdout.write(`plugin-runInWorkerFalse:reportDir=${config.reportDir}\n`)
5+
}
6+
}

test/runner/run_multiple_test.js

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -199,6 +199,23 @@ describe('CodeceptJS Multiple Runner', function () {
199199
})
200200
})
201201

202+
it('should load plugins with runInWorker:false in each child process and give each its own reportDir', done => {
203+
exec(`${runner} run-multiple --config ${codecept_dir}/codecept.multiple.plugin.runInWorkerFalse.js default`, (err, stdout) => {
204+
// Plugin must be initialised once per forked child (chrome + firefox = 2 times).
205+
// Regression: in 4.x the plugin was silently skipped because options.child was
206+
// truthy in run-multiple children, same as in worker threads.
207+
;(stdout.match(/plugin-runInWorkerFalse:loaded/g) || []).should.have.lengthOf(2)
208+
// reportDir must be replaced per child so each child writes its own report.
209+
// Regression: run-multiple.js dropped the replaceValueDeep('reportDir', ...) call
210+
// that was present in 3.x, causing all children to overwrite the same file.
211+
const dirs = (stdout.match(/plugin-runInWorkerFalse:reportDir=(.+)/g) || []).map(m => m.split('=')[1])
212+
dirs.should.have.lengthOf(2)
213+
dirs[0].should.not.equal(dirs[1])
214+
assert(!err)
215+
done()
216+
})
217+
})
218+
202219
describe('bootstrapAll and teardownAll', () => {
203220
const _codecept_run = `run-multiple --config ${codecept_dir}`
204221
it('should be executed from async function in config', done => {

0 commit comments

Comments
 (0)