Skip to content
8 changes: 8 additions & 0 deletions lib/container.js
Original file line number Diff line number Diff line change
Expand Up @@ -674,6 +674,14 @@ async function createPlugins(config, options = {}) {

// Use async loading for all plugins (ESM and CJS)
plugins[pluginName] = await loadPluginAsync(module, config[pluginName])

// Skip loading plugin in parent process if runInParent is false
if (config[pluginName].runInParent === false && process.env.RUNS_WITH_WORKERS) {
delete plugins[pluginName]
debug(`plugin ${pluginName} skipped in parent process (runInParent: false)`)
continue
}

debug(`plugin ${pluginName} loaded via async import`)
} catch (err) {
throw new Error(`Could not load plugin ${pluginName} from module '${module}':\n${err.message}\n${err.stack}`)
Expand Down
10 changes: 5 additions & 5 deletions lib/listener/globalTimeout.js
Original file line number Diff line number Diff line change
Expand Up @@ -122,15 +122,15 @@ export default function () {
if (typeof timeout !== 'number') return

if (!store.timeouts) {
debug('step', step.toCode().trim(), 'timeout disabled')
debug('step', (step.code || (typeof step.toCode === 'function' ? step.toCode() : step.name)).trim(), 'timeout disabled')
return
}

if (timeout < 0) {
debug('Previous steps timed out, setting timeout to 0.01s')
step.setTimeout(0.01, TIMEOUT_ORDER.testOrSuite)
} else {
debug(`Setting timeout ${timeout}ms for step ${step.toCode().trim()}`)
debug(`Setting timeout ${timeout}ms for step ${(step.code || (typeof step.toCode === 'function' ? step.toCode() : step.name)).trim()}`)
step.setTimeout(timeout, TIMEOUT_ORDER.testOrSuite)
}
})
Expand Down Expand Up @@ -158,17 +158,17 @@ export default function () {

event.dispatcher.on(event.step.finished, step => {
if (!store.timeouts) {
debug('step', step.toCode().trim(), 'timeout disabled')
debug('step', (step.code || (typeof step.toCode === 'function' ? step.toCode() : step.name)).trim(), 'timeout disabled')
return
}

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

debug(`step ${step.toCode().trim()}:${step.status} duration`, step.duration)
debug(`step ${(step.code || (typeof step.toCode === 'function' ? step.toCode() : step.name)).trim()}:${step.status} duration`, step.duration)
Comment thread
DenysKuchma marked this conversation as resolved.
Outdated
if (typeof timeout === 'number' && !Number.isNaN(timeout)) timeout -= step.duration

if (typeof timeout === 'number' && timeout <= 0 && recorder.isRunning()) {
debug(`step ${step.toCode().trim()} timed out`)
debug(`step ${(step.code || (typeof step.toCode === 'function' ? step.toCode() : step.name)).trim()} timed out`)
recorder.throw(new TestTimeoutError(currentTimeout))
}
})
Expand Down
1 change: 1 addition & 0 deletions lib/plugin/autoDelay.js
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ const defaultConfig = {
methods: methodsToDelay,
delayBefore: 100,
delayAfter: 200,
runInParent: false,
}

/**
Expand Down
1 change: 1 addition & 0 deletions lib/plugin/htmlReporter.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ const defaultConfig = {
keepHistory: false,
historyPath: './test-history.json',
maxHistoryEntries: 50,
runInParent: true,
}

/**
Expand Down
6 changes: 5 additions & 1 deletion lib/plugin/pauseOnFail.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,11 @@ import pause from '../pause.js'
* ```
*
*/
export default function() {
const defaultConfig = {
runInParent: false,
}

export default function(config) {
let failed = false

event.dispatcher.on(event.test.started, () => {
Expand Down
1 change: 1 addition & 0 deletions lib/plugin/retryFailedStep.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ const defaultConfig = {
defaultIgnoredSteps: ['amOnPage', 'wait*', 'send*', 'execute*', 'run*', 'have*'],
factor: 1.5,
ignoredSteps: [],
runInParent: false,
}

/**
Expand Down
1 change: 1 addition & 0 deletions lib/plugin/screenshotOnFail.js
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ const defaultConfig = {
uniqueScreenshotNames: false,
disableScreenshots: false,
fullPageScreenshots: false,
runInParent: false,
}

const supportedHelpers = Container.STANDARD_ACTING_HELPERS
Expand Down
1 change: 1 addition & 0 deletions lib/plugin/stepTimeout.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const defaultConfig = {
overrideStepLimits: false,
noTimeoutSteps: ['amOnPage', 'wait*'],
customTimeoutSteps: [],
runInParent: false,
}

/**
Expand Down
1 change: 1 addition & 0 deletions lib/step/base.js
Original file line number Diff line number Diff line change
Expand Up @@ -228,6 +228,7 @@ class Step {
startTime: step.startTime,
endTime: step.endTime,
parent,
code: step.toCode(),
}
}

Expand Down
17 changes: 17 additions & 0 deletions lib/workers.js
Original file line number Diff line number Diff line change
Expand Up @@ -626,18 +626,22 @@ class Workers extends EventEmitter {
break
case event.suite.before:
this.emit(event.suite.before, deserializeSuite(message.data))
event.dispatcher.emit(event.suite.before, deserializeSuite(message.data))
break
case event.test.before:
this.emit(event.test.before, deserializeTest(message.data))
event.dispatcher.emit(event.test.before, deserializeTest(message.data))
break
case event.test.started:
this.emit(event.test.started, deserializeTest(message.data))
event.dispatcher.emit(event.test.started, deserializeTest(message.data))
break
case event.test.failed:
// For hook failures, emit immediately as there won't be a test.finished event
// Regular test failures are handled via test.finished to support retries
if (message.data?.hookName) {
this.emit(event.test.failed, deserializeTest(message.data))
event.dispatcher.emit(event.test.failed, deserializeTest(message.data))
}
// Otherwise skip - we'll emit based on finished state
break
Expand All @@ -646,6 +650,7 @@ class Workers extends EventEmitter {
break
case event.test.skipped:
this.emit(event.test.skipped, deserializeTest(message.data))
event.dispatcher.emit(event.test.skipped, deserializeTest(message.data))
break
case event.test.finished:
// Handle different types of test completion properly
Expand All @@ -669,34 +674,42 @@ class Workers extends EventEmitter {
// For tests without UID, emit immediately
if (isFailed) {
this.emit(event.test.failed, deserializeTest(data))
event.dispatcher.emit(event.test.failed, deserializeTest(data))
} else {
this.emit(event.test.passed, deserializeTest(data))
event.dispatcher.emit(event.test.passed, deserializeTest(data))
}
}

this.emit(event.test.finished, deserializeTest(data))
event.dispatcher.emit(event.test.finished, deserializeTest(data))
}
break
case event.test.after:
this.emit(event.test.after, deserializeTest(message.data))
event.dispatcher.emit(event.test.after, deserializeTest(message.data))
break
case event.step.finished:
this.emit(event.step.finished, message.data)
break
case event.step.started:
this.emit(event.step.started, message.data)
event.dispatcher.emit(event.step.started, message.data)
break
case event.step.passed:
this.emit(event.step.passed, message.data)
event.dispatcher.emit(event.step.passed, message.data)
break
case event.step.failed:
this.emit(event.step.failed, message.data, message.data.error)
event.dispatcher.emit(event.step.failed, message.data, message.data.error)
break
case event.hook.failed:
// Hook failures are already reported as test failures by the worker
// Just emit the hook.failed event for listeners
this.emit(event.hook.failed, message.data)
break

}
})

Expand Down Expand Up @@ -759,16 +772,20 @@ class Workers extends EventEmitter {
for (const state of states) {
if (state.isFailed) {
this.emit(event.test.failed, deserializeTest(state.data))
event.dispatcher.emit(event.test.failed, deserializeTest(state.data))
} else {
this.emit(event.test.passed, deserializeTest(state.data))
event.dispatcher.emit(event.test.passed, deserializeTest(state.data))
}
}
} else {
// For non-retries (like step failures), emit only the final state
if (lastState.isFailed) {
this.emit(event.test.failed, deserializeTest(lastState.data))
event.dispatcher.emit(event.test.failed, deserializeTest(lastState.data))
} else {
this.emit(event.test.passed, deserializeTest(lastState.data))
event.dispatcher.emit(event.test.passed, deserializeTest(lastState.data))
}
}
}
Expand Down
Loading