@@ -144,6 +144,88 @@ class ChildWithOverridePostConstruct extends ParentWithPostConstruct {
144144 }
145145}
146146
147+ // Additional test classes for comprehensive async PostConstruct testing
148+ @Component ( )
149+ class GrandChildWithAsyncPostConstruct extends ChildWithAsyncPostConstruct {
150+ // async initialize inherited through 2 levels
151+ }
152+
153+ @Component ( )
154+ class MultipleAsyncPostConstruct {
155+ public step1Complete = false ;
156+
157+ public step2Complete = false ;
158+
159+ public step3Complete = false ;
160+
161+ @PostConstruct ( )
162+ public async initStep1 ( ) {
163+ await new Promise ( ( resolve ) => {
164+ setTimeout ( resolve , 50 ) ;
165+ } ) ;
166+ this . step1Complete = true ;
167+ }
168+
169+ @PostConstruct ( )
170+ public async initStep2 ( ) {
171+ await new Promise ( ( resolve ) => {
172+ setTimeout ( resolve , 50 ) ;
173+ } ) ;
174+ this . step2Complete = true ;
175+ }
176+
177+ @PostConstruct ( )
178+ public async initStep3 ( ) {
179+ await new Promise ( ( resolve ) => {
180+ setTimeout ( resolve , 50 ) ;
181+ } ) ;
182+ this . step3Complete = true ;
183+ }
184+ }
185+
186+ @Component ( )
187+ class MixedSyncAsyncPostConstruct {
188+ public syncComplete = false ;
189+
190+ public asyncComplete = false ;
191+
192+ public executionOrder : string [ ] = [ ] ;
193+
194+ @PostConstruct ( )
195+ public syncInit ( ) {
196+ this . syncComplete = true ;
197+ this . executionOrder . push ( 'sync' ) ;
198+ }
199+
200+ @PostConstruct ( )
201+ public async asyncInit ( ) {
202+ await new Promise ( ( resolve ) => {
203+ setTimeout ( resolve , 100 ) ;
204+ } ) ;
205+ this . asyncComplete = true ;
206+ this . executionOrder . push ( 'async' ) ;
207+ }
208+ }
209+
210+ @Component ( )
211+ class AsyncPostConstructWithDependency {
212+ public isInitialized = false ;
213+
214+ public dependencyValue = '' ;
215+
216+ @Inject ( TestClass )
217+ private testClass ! : TestClass ;
218+
219+ @PostConstruct ( )
220+ public async init ( ) {
221+ await new Promise ( ( resolve ) => {
222+ setTimeout ( resolve , 50 ) ;
223+ } ) ;
224+ this . dependencyValue = this . testClass . testMethod ( ) ;
225+ this . isInitialized = true ;
226+ }
227+ }
228+
147229describe ( 'Container' , ( ) => {
148230 let container : Container ;
149231
@@ -301,12 +383,20 @@ describe('Container', () => {
301383 } ) ;
302384
303385 test ( 'should properly await async PostConstruct for inherited async methods' , async ( ) => {
386+ const startTime = Date . now ( ) ;
387+
304388 await container . register ( 'ChildWithAsyncPostConstruct' , ChildWithAsyncPostConstruct , true ) ;
305389
306390 const instance = ( await container . resolve ( 'ChildWithAsyncPostConstruct' ) ) as ChildWithAsyncPostConstruct ;
307391
308392 expect ( instance ) . toBeInstanceOf ( ChildWithAsyncPostConstruct ) ;
309393 expect ( instance . isReady ) . toBe ( true ) ;
394+ expect ( instance . initTime ) . toBeGreaterThan ( 0 ) ;
395+
396+ // Verify that async PostConstruct was actually awaited (at least 95ms delay, with some tolerance)
397+ const elapsedTime = Date . now ( ) - startTime ;
398+
399+ expect ( elapsedTime ) . toBeGreaterThanOrEqual ( 95 ) ;
310400 } ) ;
311401
312402 test ( 'should execute overridden PostConstruct correctly' , async ( ) => {
@@ -421,4 +511,115 @@ describe('Container', () => {
421511 expect ( userService . logger ) . toBe ( logger ) ;
422512 expect ( userService . getUser ( ) ) . toBe ( 'LOG: Getting user' ) ;
423513 } ) ;
514+
515+ // Comprehensive async PostConstruct tests
516+ test ( 'should properly await async PostConstruct through multiple inheritance levels' , async ( ) => {
517+ const startTime = Date . now ( ) ;
518+
519+ await container . register ( 'GrandChildWithAsyncPostConstruct' , GrandChildWithAsyncPostConstruct , true ) ;
520+
521+ const instance = ( await container . resolve (
522+ 'GrandChildWithAsyncPostConstruct' ,
523+ ) ) as GrandChildWithAsyncPostConstruct ;
524+
525+ expect ( instance ) . toBeInstanceOf ( GrandChildWithAsyncPostConstruct ) ;
526+ expect ( instance . isReady ) . toBe ( true ) ;
527+ expect ( instance . initTime ) . toBeGreaterThan ( 0 ) ;
528+
529+ // Verify async PostConstruct was awaited through 2 inheritance levels
530+ const elapsedTime = Date . now ( ) - startTime ;
531+
532+ expect ( elapsedTime ) . toBeGreaterThanOrEqual ( 100 ) ;
533+ } ) ;
534+
535+ test ( 'should properly await multiple async PostConstruct methods' , async ( ) => {
536+ const startTime = Date . now ( ) ;
537+
538+ await container . register ( 'MultipleAsyncPostConstruct' , MultipleAsyncPostConstruct , true ) ;
539+
540+ const instance = ( await container . resolve ( 'MultipleAsyncPostConstruct' ) ) as MultipleAsyncPostConstruct ;
541+
542+ expect ( instance ) . toBeInstanceOf ( MultipleAsyncPostConstruct ) ;
543+ expect ( instance . step1Complete ) . toBe ( true ) ;
544+ expect ( instance . step2Complete ) . toBe ( true ) ;
545+ expect ( instance . step3Complete ) . toBe ( true ) ;
546+
547+ // All three PostConstruct methods should have been awaited (3 * 50ms = 150ms minimum)
548+ const elapsedTime = Date . now ( ) - startTime ;
549+
550+ expect ( elapsedTime ) . toBeGreaterThanOrEqual ( 150 ) ;
551+ } ) ;
552+
553+ test ( 'should properly handle mixed sync and async PostConstruct methods' , async ( ) => {
554+ await container . register ( 'MixedSyncAsyncPostConstruct' , MixedSyncAsyncPostConstruct , true ) ;
555+
556+ const instance = ( await container . resolve ( 'MixedSyncAsyncPostConstruct' ) ) as MixedSyncAsyncPostConstruct ;
557+
558+ expect ( instance ) . toBeInstanceOf ( MixedSyncAsyncPostConstruct ) ;
559+ expect ( instance . syncComplete ) . toBe ( true ) ;
560+ expect ( instance . asyncComplete ) . toBe ( true ) ;
561+
562+ // Both sync and async PostConstruct should execute
563+ expect ( instance . executionOrder ) . toContain ( 'sync' ) ;
564+ expect ( instance . executionOrder ) . toContain ( 'async' ) ;
565+ expect ( instance . executionOrder . length ) . toBe ( 2 ) ;
566+ } ) ;
567+
568+ test ( 'should inject dependencies before async PostConstruct execution' , async ( ) => {
569+ await container . register ( 'AsyncPostConstructWithDependency' , AsyncPostConstructWithDependency , true ) ;
570+
571+ const instance = ( await container . resolve ( 'AsyncPostConstructWithDependency' ) ) as AsyncPostConstructWithDependency ;
572+
573+ expect ( instance ) . toBeInstanceOf ( AsyncPostConstructWithDependency ) ;
574+ expect ( instance . isInitialized ) . toBe ( true ) ;
575+ // Dependency should have been injected before PostConstruct
576+ expect ( instance . dependencyValue ) . toBe ( 'test' ) ;
577+ } ) ;
578+
579+ test ( 'should handle sequential resolution of multiple prototype instances with async PostConstruct' , async ( ) => {
580+ await container . register ( 'BaseWithAsyncPostConstruct' , BaseWithAsyncPostConstruct , false ) ; // prototype
581+
582+ // Resolve multiple instances sequentially
583+ const instance1 = ( await container . resolve ( 'BaseWithAsyncPostConstruct' ) ) as BaseWithAsyncPostConstruct ;
584+ const instance2 = ( await container . resolve ( 'BaseWithAsyncPostConstruct' ) ) as BaseWithAsyncPostConstruct ;
585+ const instance3 = ( await container . resolve ( 'BaseWithAsyncPostConstruct' ) ) as BaseWithAsyncPostConstruct ;
586+
587+ // All instances should be properly initialized
588+ expect ( instance1 . isReady ) . toBe ( true ) ;
589+ expect ( instance2 . isReady ) . toBe ( true ) ;
590+ expect ( instance3 . isReady ) . toBe ( true ) ;
591+
592+ // They should be different instances
593+ expect ( instance1 ) . not . toBe ( instance2 ) ;
594+ expect ( instance2 ) . not . toBe ( instance3 ) ;
595+ expect ( instance1 ) . not . toBe ( instance3 ) ;
596+
597+ // Each should have their own initTime
598+ expect ( instance1 . initTime ) . toBeGreaterThan ( 0 ) ;
599+ expect ( instance2 . initTime ) . toBeGreaterThan ( 0 ) ;
600+ expect ( instance3 . initTime ) . toBeGreaterThan ( 0 ) ;
601+
602+ // Later instances should have equal or later initTime
603+ expect ( instance2 . initTime ) . toBeGreaterThanOrEqual ( instance1 . initTime ) ;
604+ expect ( instance3 . initTime ) . toBeGreaterThanOrEqual ( instance2 . initTime ) ;
605+ } ) ;
606+
607+ test ( 'should handle async PostConstruct in prototype scope correctly' , async ( ) => {
608+ await container . register ( 'ChildWithAsyncPostConstruct' , ChildWithAsyncPostConstruct , false ) ; // prototype
609+
610+ const instance1 = ( await container . resolve ( 'ChildWithAsyncPostConstruct' ) ) as ChildWithAsyncPostConstruct ;
611+ const instance2 = ( await container . resolve ( 'ChildWithAsyncPostConstruct' ) ) as ChildWithAsyncPostConstruct ;
612+
613+ // Both instances should be fully initialized
614+ expect ( instance1 . isReady ) . toBe ( true ) ;
615+ expect ( instance2 . isReady ) . toBe ( true ) ;
616+
617+ // They should be different instances
618+ expect ( instance1 ) . not . toBe ( instance2 ) ;
619+
620+ // Each should have their own initTime
621+ expect ( instance1 . initTime ) . toBeGreaterThan ( 0 ) ;
622+ expect ( instance2 . initTime ) . toBeGreaterThan ( 0 ) ;
623+ expect ( instance2 . initTime ) . toBeGreaterThanOrEqual ( instance1 . initTime ) ;
624+ } ) ;
424625} ) ;
0 commit comments