【问题标题】:Angular 10 testing ViewContainerRef's injector returns undefinedAngular 10 测试 ViewContainerRef 的注入器返回未定义
【发布时间】:2020-12-18 10:31:47
【问题描述】:

问题是在将我们的项目从 Angular 8.2.14 迁移到 Angular 10.2.24 之后发生的。

这是测试代码

fdescribe('PopupModalService Testing', () => {
    let componentFactoryResolver: ComponentFactoryResolver;
    let viewContainerRef: ViewContainerRef;
    let popupModalService: PopupModalService;

    beforeEach(waitForAsync(() => {
        const viewContainerRefSpy = jasmine.createSpyObj('ViewContainerRef', ['insert']);

        TestBed.configureTestingModule({
            declarations: [
                PopupModalComponent,
                DialogApiComponent,
                BrokerFormPopoverComponent,
                BrokerContextMenuComponent
            ],
            imports: [
                ReactiveFormsModule,
                TranslateModule.forRoot()
            ],
            providers: [
                { provide: ViewContainerRef, useValue: viewContainerRefSpy },
                PopupModalService
            ],
            schemas: [
                NO_ERRORS_SCHEMA
            ]
        });

        TestBed.overrideModule(BrowserDynamicTestingModule, {
            set: {
                entryComponents: [
                    PopupModalComponent,
                    DialogApiComponent,
                    BrokerFormPopoverComponent,
                    BrokerContextMenuComponent
                ]
            }
        });

        componentFactoryResolver = TestBed.inject(ComponentFactoryResolver);
        viewContainerRef = TestBed.inject(ViewContainerRef);
        popupModalService = new PopupModalService(componentFactoryResolver);
    }));

    it('should create PopupModalComponent', () => {
        expect(popupModalService.create(viewContainerRef, ModalType.SIMPLE, 'Test Title', 'Test Content', PopupActionType.SAVE)).toBeDefined();
    });

    it('should create BrokerContextMenuComponent', () => {
        expect(popupModalService.createBrokerContextMenu(viewContainerRef, 999, 999)).toBeDefined();
    });
});

这是组件的代码

@Injectable({
    providedIn: 'root'
})
export class PopupModalService {

    factoryResolver: ComponentFactoryResolver;

    constructor(@Inject(ComponentFactoryResolver) factoryResolver) {
        this.factoryResolver = factoryResolver;
    }

    create(
        viewContainer: ViewContainerRef,
        modalType: ModalType,
        title: string,
        content: string,
        popupActionType?: PopupActionType): PopupModalComponent {

        const factory = this.factoryResolver.resolveComponentFactory(PopupModalComponent);
        const popupRef = factory.create(viewContainer.injector);
        const popup = popupRef.instance;
        popup.modalType = modalType;
        popup.title = title;
        popup.content = content;
        popup.setComponentRef(popupRef);
        popup.popupActionType = popupActionType;
        popup.hide();
        viewContainer.insert(popupRef.hostView);
        popup.initFormValue();
        return popup;
    }
}

添加一些日志后看看哪个部分是undefined,其实是viewContainer.injector是未定义的。

此代码过去确实有效,只是在迁移后无法运行。

我试过了

请帮助解决问题。

【问题讨论】:

    标签: angular typescript unit-testing karma-jasmine


    【解决方案1】:

    我仍然找不到它在 Angular 10 上不起作用的原因。但是,我的想法是用 TestBed 替换 undefined 注入器。我发现TestBed 本身就是Injector

    在测试代码中,我将这一行改为

    expect(popupModalService.create(viewContainerRef, ModalType.SIMPLE, 'Test Title', 'Test Content', PopupActionType.SAVE)).toBeDefined();
    

    expect(popupModalService.create(viewContainerRef, ModalType.SIMPLE, 'Test Title', 'Test Content', PopupActionType.SAVE, TestBed)).toBeDefined();
    

    并在PopupModalService 中,将create 方法更改为

        create(
            viewContainer: ViewContainerRef,
            modalType: ModalType,
            title: string,
            content: string,
            popupActionType?: PopupActionType,
            injector?: Injector): PopupModalComponent {
    
            const factory = this.factoryResolver.resolveComponentFactory(PopupModalComponent);
            const popupRef = factory.create(injector === undefined ? viewContainer.injector : injector);
            const popup = popupRef.instance;
            popup.modalType = modalType;
            popup.title = title;
            popup.content = content;
            popup.setComponentRef(popupRef);
            popup.popupActionType = popupActionType;
            popup.hide();
            viewContainer.insert(popupRef.hostView);
            popup.initFormValue();
            return popup;
        }
    

    我将最后一个参数injector 设为可选,这将保持现有代码正常工作而无需任何更改。

    更新:更好的是,我们可以只更新测试代码,像这样

    const viewContainerRefSpy = jasmine.createSpyObj('ViewContainerRef', ['insert'], {'injector': TestBed});
    

    这个和上面一样,好处是我们不碰正常的代码,我们只改变测试代码。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-10-31
      • 2016-04-29
      • 1970-01-01
      • 2019-02-12
      • 2019-11-11
      • 1970-01-01
      相关资源
      最近更新 更多