|
7 | 7 | */
|
8 | 8 |
|
9 | 9 | import {CommonModule} from '@angular/common';
|
10 |
| -import {Attribute, ChangeDetectorRef, Component, ComponentFactoryResolver, ComponentRef, createEnvironmentInjector, createNgModule, Directive, ElementRef, ENVIRONMENT_INITIALIZER, EnvironmentInjector, EventEmitter, forwardRef, Host, HostBinding, ImportedNgModuleProviders, importProvidersFrom, ImportProvidersSource, inject, Inject, Injectable, InjectFlags, InjectionToken, InjectOptions, INJECTOR, Injector, Input, LOCALE_ID, makeEnvironmentProviders, ModuleWithProviders, NgModule, NgZone, Optional, Output, Pipe, PipeTransform, Provider, Self, SkipSelf, TemplateRef, Type, ViewChild, ViewContainerRef, ViewEncapsulation, ViewRef, ɵcreateInjector as createInjector, ɵDEFAULT_LOCALE_ID as DEFAULT_LOCALE_ID, ɵINJECTOR_SCOPE, ɵInternalEnvironmentProviders as InternalEnvironmentProviders} from '@angular/core'; |
| 10 | +import {Attribute, ChangeDetectorRef, Component, ComponentFactoryResolver, ComponentRef, createEnvironmentInjector, createNgModule, Directive, ElementRef, ENVIRONMENT_INITIALIZER, EnvironmentInjector, EventEmitter, forwardRef, Host, HostBinding, ImportedNgModuleProviders, importProvidersFrom, ImportProvidersSource, inject, Inject, Injectable, InjectFlags, InjectionToken, InjectOptions, INJECTOR, Injector, Input, LOCALE_ID, makeEnvironmentProviders, ModuleWithProviders, NgModule, NgModuleRef, NgZone, Optional, Output, Pipe, PipeTransform, Provider, runInInjectionContext, Self, SkipSelf, TemplateRef, Type, ViewChild, ViewContainerRef, ViewEncapsulation, ViewRef, ɵcreateInjector as createInjector, ɵDEFAULT_LOCALE_ID as DEFAULT_LOCALE_ID, ɵINJECTOR_SCOPE, ɵInternalEnvironmentProviders as InternalEnvironmentProviders} from '@angular/core'; |
11 | 11 | import {ViewRef as ViewRefInternal} from '@angular/core/src/render3/view_ref';
|
12 | 12 | import {TestBed} from '@angular/core/testing';
|
13 | 13 | import {By} from '@angular/platform-browser';
|
@@ -3691,6 +3691,125 @@ describe('di', () => {
|
3691 | 3691 | });
|
3692 | 3692 | });
|
3693 | 3693 |
|
| 3694 | + describe('runInInjectionContext', () => { |
| 3695 | + it('should return the function\'s return value', () => { |
| 3696 | + const injector = TestBed.inject(EnvironmentInjector); |
| 3697 | + const returnValue = runInInjectionContext(injector, () => 3); |
| 3698 | + expect(returnValue).toBe(3); |
| 3699 | + }); |
| 3700 | + |
| 3701 | + it('should work with an NgModuleRef injector', () => { |
| 3702 | + const ref = TestBed.inject(NgModuleRef); |
| 3703 | + const returnValue = runInInjectionContext(ref.injector, () => 3); |
| 3704 | + expect(returnValue).toBe(3); |
| 3705 | + }); |
| 3706 | + |
| 3707 | + it('should return correct injector reference', () => { |
| 3708 | + const ngModuleRef = TestBed.inject(NgModuleRef); |
| 3709 | + const ref1 = runInInjectionContext(ngModuleRef.injector, () => inject(Injector)); |
| 3710 | + const ref2 = ngModuleRef.injector.get(Injector); |
| 3711 | + expect(ref1).toBe(ref2); |
| 3712 | + }); |
| 3713 | + |
| 3714 | + it('should make inject() available', () => { |
| 3715 | + const TOKEN = new InjectionToken<string>('TOKEN'); |
| 3716 | + const injector = createEnvironmentInjector( |
| 3717 | + [{provide: TOKEN, useValue: 'from injector'}], TestBed.inject(EnvironmentInjector)); |
| 3718 | + |
| 3719 | + const result = runInInjectionContext(injector, () => inject(TOKEN)); |
| 3720 | + expect(result).toEqual('from injector'); |
| 3721 | + }); |
| 3722 | + |
| 3723 | + it('should properly clean up after the function returns', () => { |
| 3724 | + const TOKEN = new InjectionToken<string>('TOKEN'); |
| 3725 | + const injector = TestBed.inject(EnvironmentInjector); |
| 3726 | + runInInjectionContext(injector, () => {}); |
| 3727 | + expect(() => inject(TOKEN, InjectFlags.Optional)).toThrow(); |
| 3728 | + }); |
| 3729 | + |
| 3730 | + it('should properly clean up after the function throws', () => { |
| 3731 | + const TOKEN = new InjectionToken<string>('TOKEN'); |
| 3732 | + const injector = TestBed.inject(EnvironmentInjector); |
| 3733 | + expect(() => runInInjectionContext(injector, () => { |
| 3734 | + throw new Error('crashes!'); |
| 3735 | + })).toThrow(); |
| 3736 | + expect(() => inject(TOKEN, InjectFlags.Optional)).toThrow(); |
| 3737 | + }); |
| 3738 | + |
| 3739 | + it('should set the correct inject implementation', () => { |
| 3740 | + const TOKEN = new InjectionToken<string>('TOKEN', { |
| 3741 | + providedIn: 'root', |
| 3742 | + factory: () => 'from root', |
| 3743 | + }); |
| 3744 | + |
| 3745 | + @Component({ |
| 3746 | + standalone: true, |
| 3747 | + template: '', |
| 3748 | + providers: [{provide: TOKEN, useValue: 'from component'}], |
| 3749 | + }) |
| 3750 | + class TestCmp { |
| 3751 | + envInjector = inject(EnvironmentInjector); |
| 3752 | + |
| 3753 | + tokenFromComponent = inject(TOKEN); |
| 3754 | + tokenFromEnvContext = runInInjectionContext(this.envInjector, () => inject(TOKEN)); |
| 3755 | + |
| 3756 | + // Attempt to inject ViewContainerRef within the environment injector's context. This should |
| 3757 | + // not be available, so the result should be `null`. |
| 3758 | + vcrFromEnvContext = runInInjectionContext( |
| 3759 | + this.envInjector, () => inject(ViewContainerRef, InjectFlags.Optional)); |
| 3760 | + } |
| 3761 | + |
| 3762 | + const instance = TestBed.createComponent(TestCmp).componentInstance; |
| 3763 | + expect(instance.tokenFromComponent).toEqual('from component'); |
| 3764 | + expect(instance.tokenFromEnvContext).toEqual('from root'); |
| 3765 | + expect(instance.vcrFromEnvContext).toBeNull(); |
| 3766 | + }); |
| 3767 | + |
| 3768 | + it('should support node injectors', () => { |
| 3769 | + @Component({ |
| 3770 | + standalone: true, |
| 3771 | + template: '', |
| 3772 | + }) |
| 3773 | + class TestCmp { |
| 3774 | + injector = inject(Injector); |
| 3775 | + |
| 3776 | + vcrFromEnvContext = |
| 3777 | + runInInjectionContext(this.injector, () => inject(ViewContainerRef, {optional: true})); |
| 3778 | + } |
| 3779 | + |
| 3780 | + const instance = TestBed.createComponent(TestCmp).componentInstance; |
| 3781 | + expect(instance.vcrFromEnvContext).not.toBeNull(); |
| 3782 | + }); |
| 3783 | + |
| 3784 | + it('should be reentrant', () => { |
| 3785 | + const TOKEN = new InjectionToken<string>('TOKEN', { |
| 3786 | + providedIn: 'root', |
| 3787 | + factory: () => 'from root', |
| 3788 | + }); |
| 3789 | + |
| 3790 | + const parentInjector = TestBed.inject(EnvironmentInjector); |
| 3791 | + const childInjector = |
| 3792 | + createEnvironmentInjector([{provide: TOKEN, useValue: 'from child'}], parentInjector); |
| 3793 | + |
| 3794 | + const results = runInInjectionContext(parentInjector, () => { |
| 3795 | + const fromParentBefore = inject(TOKEN); |
| 3796 | + const fromChild = runInInjectionContext(childInjector, () => inject(TOKEN)); |
| 3797 | + const fromParentAfter = inject(TOKEN); |
| 3798 | + return {fromParentBefore, fromChild, fromParentAfter}; |
| 3799 | + }); |
| 3800 | + |
| 3801 | + expect(results.fromParentBefore).toEqual('from root'); |
| 3802 | + expect(results.fromChild).toEqual('from child'); |
| 3803 | + expect(results.fromParentAfter).toEqual('from root'); |
| 3804 | + }); |
| 3805 | + |
| 3806 | + it('should not function on a destroyed injector', () => { |
| 3807 | + const injector = createEnvironmentInjector([], TestBed.inject(EnvironmentInjector)); |
| 3808 | + injector.destroy(); |
| 3809 | + expect(() => runInInjectionContext(injector, () => {})).toThrow(); |
| 3810 | + }); |
| 3811 | + }); |
| 3812 | + |
3694 | 3813 | it('should be able to use Host in `useFactory` dependency config', () => {
|
3695 | 3814 | // Scenario:
|
3696 | 3815 | // ---------
|
|
0 commit comments