@@ -68,7 +68,44 @@ class Container {
6868 container . plugins = await createPlugins ( config . plugins || { } , opts )
6969 container . result = new Result ( )
7070
71- createActor ( config . include ?. I )
71+ // Preload includes (so proxies can expose real objects synchronously)
72+ const includes = config . include || { }
73+
74+ // Ensure I is available for DI modules at import time
75+ if ( Object . prototype . hasOwnProperty . call ( includes , 'I' ) ) {
76+ try {
77+ const mod = includes . I
78+ if ( typeof mod === 'string' ) {
79+ container . support . I = await loadSupportObject ( mod , 'I' )
80+ } else if ( typeof mod === 'function' ) {
81+ container . support . I = await loadSupportObject ( mod , 'I' )
82+ } else if ( mod && typeof mod === 'object' ) {
83+ container . support . I = mod
84+ }
85+ } catch ( e ) {
86+ throw new Error ( `Could not include object I: ${ e . message } ` )
87+ }
88+ } else {
89+ // Create default actor if not provided via includes
90+ createActor ( )
91+ }
92+
93+ // Load remaining includes except I
94+ for ( const [ name , mod ] of Object . entries ( includes ) ) {
95+ if ( name === 'I' ) continue
96+ try {
97+ if ( typeof mod === 'string' ) {
98+ container . support [ name ] = await loadSupportObject ( mod , name )
99+ } else if ( typeof mod === 'function' ) {
100+ // function or class
101+ container . support [ name ] = await loadSupportObject ( mod , name )
102+ } else if ( mod && typeof mod === 'object' ) {
103+ container . support [ name ] = mod
104+ }
105+ } catch ( e ) {
106+ throw new Error ( `Could not include object ${ name } : ${ e . message } ` )
107+ }
108+ }
72109
73110 if ( opts && opts . ai ) ai . enable ( config . ai ) // enable AI Assistant
74111 if ( config . gherkin ) await loadGherkinStepsAsync ( config . gherkin . steps || [ ] )
@@ -228,7 +265,7 @@ function createHelpers(config) {
228265 }
229266
230267 // ESM import (legacy check)
231- if ( ! HelperClass && helperName ?. constructor === Function && helperName . prototype ) {
268+ if ( ! HelperClass && typeof helperName === 'function' && helperName . prototype ) {
232269 HelperClass = helperName
233270 helperName = HelperClass . constructor . name
234271 }
@@ -445,7 +482,7 @@ function createSupportObjects(config) {
445482 return {
446483 enumerable : true ,
447484 configurable : true ,
448- value : this . get ( target , prop ) ,
485+ value : container . support [ name ] [ prop ] ,
449486 }
450487 } ,
451488 ownKeys ( ) {
@@ -472,10 +509,21 @@ function createSupportObjects(config) {
472509 return {
473510 enumerable : true ,
474511 configurable : true ,
475- value : this . get ( target , prop ) ,
512+ value : target [ prop ] ,
476513 }
477514 } ,
478515 get ( target , key ) {
516+ if ( typeof key === 'symbol' ) {
517+ // safely ignore symbol-based meta properties used by tooling
518+ return undefined
519+ }
520+ // Allow special I even if not declared in includes
521+ if ( key === 'I' ) {
522+ return lazyLoad ( 'I' )
523+ }
524+ if ( ! keys . includes ( key ) ) {
525+ throw new Error ( `Support object "${ String ( key ) } " is not defined` )
526+ }
479527 return lazyLoad ( key )
480528 } ,
481529 } ,
@@ -485,12 +533,8 @@ function createSupportObjects(config) {
485533function createActor ( actorPath ) {
486534 if ( container . support . I ) return container . support . I
487535
488- if ( actorPath ) {
489- // Actor path loading must be handled async during container creation
490- throw new Error ( `Custom actor loading from path '${ actorPath } ' must be handled asynchronously during container creation` )
491- } else {
492- container . support . I = actorFactory ( { } , Container )
493- }
536+ // Default actor
537+ container . support . I = actorFactory ( { } , Container )
494538
495539 return container . support . I
496540}
@@ -508,7 +552,7 @@ async function loadPluginAsync(modulePath, config) {
508552 if ( typeof pluginFactory !== 'function' ) {
509553 throw new Error ( `Plugin '${ modulePath } ' is not a function. Expected a plugin factory function.` )
510554 }
511-
555+
512556 return pluginFactory ( config )
513557}
514558
@@ -537,7 +581,7 @@ async function createPlugins(config, options = {}) {
537581 } else {
538582 module = `./plugin/${ pluginName } .js`
539583 }
540-
584+
541585 // Use async loading for all plugins (ESM and CJS)
542586 plugins [ pluginName ] = await loadPluginAsync ( module , config [ pluginName ] )
543587 debug ( `plugin ${ pluginName } loaded via async import` )
@@ -592,12 +636,31 @@ async function loadSupportObject(modulePath, supportObjectName) {
592636 if ( ! modulePath ) {
593637 throw new Error ( `Support object "${ supportObjectName } " is not defined` )
594638 }
595- if ( modulePath . charAt ( 0 ) === '.' ) {
639+ // If function/class provided directly
640+ if ( typeof modulePath === 'function' ) {
641+ try {
642+ // class constructor
643+ if ( modulePath . prototype && modulePath . prototype . constructor === modulePath ) {
644+ return new modulePath ( )
645+ }
646+ // plain function factory
647+ return modulePath ( )
648+ } catch ( err ) {
649+ throw new Error ( `Could not include object ${ supportObjectName } from function: ${ err . message } ` )
650+ }
651+ }
652+ if ( typeof modulePath === 'string' && modulePath . charAt ( 0 ) === '.' ) {
596653 modulePath = path . join ( global . codecept_dir , modulePath )
597654 }
598655 try {
599656 // Use dynamic import for both ESM and CJS modules
600- const obj = await import ( modulePath )
657+ let importPath = modulePath
658+ // Append .js if no extension provided (ESM resolution requires it)
659+ if ( typeof importPath === 'string' ) {
660+ const ext = path . extname ( importPath )
661+ if ( ! ext ) importPath = `${ importPath } .js`
662+ }
663+ const obj = await import ( importPath )
601664
602665 // Handle ESM module wrapper
603666 let actualObj = obj
0 commit comments