Angular指令通过inject获取宿主组件后Jest测试报NG0203错误求助
解决Angular指令中
inject()在Jest测试里的NG0203错误 问题场景
我有一个指令,通过inject关键字获取继承自抽象组件MyBaseComponent的实例,指令代码如下:
export class MyDirective implements AfterViewInit { private component: MyBaseComponent = inject(MyBaseComponent); ... }
使用时直接在子组件模板上应用指令:
<my-text-component my-directive> </my-text-component>
正常运行时component能正确指向my-text-component实例,但Jest单元测试时触发错误,测试代码如下:
describe("MyDirectiveTest", () => { let directive: MyDirective; beforeEach(() => { TestBed.configureTestingModule({ declarations: [MyDirective, MyBaseComponent, MyTextComponent], providers: [{ provide: MyBaseComponent, useClass: MyTextComponent }], }); directive = new MyDirective(); }); it("should initialize correctly", () => { expect(directive).toBeTruthy(); }); });
错误信息:
NG0203: inject() must be called from an injection context such as a constructor, a factory function, a field initializer, or a function used with
runInInjectionContext.
已尝试给指令添加@Injectable()装饰器,无效果。
原因分析
直接用new MyDirective()手动创建实例时,脱离了Angular的注入上下文环境,inject()无法找到对应的依赖提供者,因此触发报错。指令的依赖必须通过TestBed的注入机制获取,不能手动实例化。
解决方案
方案1:模拟真实场景,用宿主组件承载指令
这种方式最贴近实际运行逻辑,因为指令本身就是依附在组件上生效的:
describe("MyDirectiveTest", () => { let fixture: ComponentFixture<TestHostComponent>; let directive: MyDirective; let textComponent: MyTextComponent; // 创建测试宿主组件,用来模拟指令的实际使用场景 @Component({ template: `<my-text-component my-directive></my-text-component>` }) class TestHostComponent {} beforeEach(() => { TestBed.configureTestingModule({ declarations: [ MyDirective, MyBaseComponent, MyTextComponent, TestHostComponent ] }); fixture = TestBed.createComponent(TestHostComponent); fixture.detectChanges(); // 触发组件初始化 // 从DOM元素中查询获取指令和组件实例 textComponent = fixture.debugElement.query(By.directive(MyTextComponent)).componentInstance; directive = fixture.debugElement.query(By.directive(MyDirective)).injector.get(MyDirective); }); it("should initialize correctly", () => { expect(directive).toBeTruthy(); // 验证指令获取的component是正确的MyTextComponent实例 expect(directive['component']).toBe(textComponent); }); });
方案2:用runInInjectionContext包裹实例化
如果只想单独测试指令逻辑,不想依赖组件模板,可以用此方法确保inject()在正确上下文执行:
describe("MyDirectiveTest", () => { let directive: MyDirective; beforeEach(() => { TestBed.configureTestingModule({ declarations: [MyDirective, MyBaseComponent, MyTextComponent], providers: [{ provide: MyBaseComponent, useClass: MyTextComponent }], }); const injector = TestBed.inject(Injector); directive = runInInjectionContext(injector, () => new MyDirective()); }); it("should initialize correctly", () => { expect(directive).toBeTruthy(); }); });
关键要点
- 指令中
inject(MyBaseComponent)的本质是获取指令所在元素的组件实例,测试时必须模拟这种层级依赖关系。 - 永远不要手动
newAngular的指令/组件实例,必须通过TestBed的注入机制或组件Fixture来获取实例,保证依赖注入上下文的正确性。
内容的提问来源于stack exchange,提问作者A.B.
相关产品推荐
相关产品推荐

