Angular 10测试ViewContainerRef的注射器返回未定义 [英] Angular 10 testing ViewContainerRef's injector returns undefined

查看:79
本文介绍了Angular 10测试ViewContainerRef的注射器返回未定义的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题从我们的项目从Angular 8.2.14迁移到Angular 10.2.24之后发生.

The problem happens after migrating our project from Angular 8.2.14 to 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是未定义的部分.

After adding some logs to see which part is undefined, it's actually the viewContainer.injector is the undefined one.

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

This code did work in past, it only failed to run after the migration.

我尝试过

  • Angular Directive ViewContainerRef Test Mock.
  • https://angular2.programmingpedia.net/en/tutorial/831/dynamically-add-components-using-viewcontainerref-createcomponent

请帮助解决该问题.

推荐答案

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

I still can't find the reason one it doesn't work on Angular 10. However, my idea is to replace the undefined injector by TestBed. I've discovered that TestBed is a Injector itself.

在测试代码中,我将更改此行

In the test code, I will change this line from

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方法更改为

and in the PopupModalService, change the create method to

    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设为可选,这将使现有代码保持正常运行,而无需进行任何更改.

I make the last param injector optional, this will keep the existing code work normally without any changes.

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

UPDATE: Better yet, we can update only the test code, like this

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

这与上面的工作原理相同,好处是我们不触摸普通代码,只更改测试代码.

This works the same as above, the benefit is we don't touch the normal code, we only change the test code.

这篇关于Angular 10测试ViewContainerRef的注射器返回未定义的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆