Angular Jasmine 测试:使用 setTimeout 时规范没有预期

Angular Jasmine Test: SPEC HAS NO EXPECTATIONS when using setTimeout

我正在尝试为我的应用程序中的组件编写单元测试。这是一个名为 TroubleShootingPage 的非常简单的组件,如果有人在我的应用程序的其余部分遇到问题,它只会显示一个帮助页面。

所有测试都通过了,但在 Karma 的输出中我看到一个提示:SPEC HAS NO EXPECTATIONS:

本应没有期望的测试正在处理我的 TroubleShootingPage 组件中的函数 getTroubleShootingPage(),它看起来像这样:

export interface Entry<T> {
    sys: Sys;
    fields: T;
    toPlainObject(): object;
    update(): Promise<Entry<T>>;
}

troubleShootingPage: Entry<any>;

constructor(private contentfulService: ContentfulService) {}

ngOnInit() {
    this.getTroubleShootingPage("en-US")
}

getTroubleShootingPage(locale: string) {
    this.contentfulService.getTroubleShootingPage(locale).then(page => {
      this.troubleShootingPage = page;
      ...
  }
}

如您所见,故障排除页面的 content/text 必须从 contentfulService 加载,并且根据用户的语言从 API (Contentful) 加载。所以我只想确保函数被调用并且从 contentfulService 返回的输入被正确分配给变量 this.troubleShootingPage.

测试看起来像这样:

describe('TroubleshootingPageComponent', () => {
    let component: TroubleshootingPageComponent;
    let fixture: ComponentFixture<TroubleshootingPageComponent>;
    
    let contentfulServiceStub: Partial<ContentfulService> = {
        getTroubleShootingPage: () => {
            return new Promise<Entry<any>>(() => {
                return troubleShootingPageMock;
            });
        }
    };

    let troubleShootingPageMock: Entry<any>;
    troubleShootingPageMock = {
        fields: {
            description: "Please read here for further help:",
            mainText: {},
            textCancelButton: "Quit",
            textConfirmButton: "Continue",
            title: "Need Help?"
        },
        toPlainObject() {
            return null;
        },
        update() {
            return null;
        },
        sys: {
            type: "",
            id: "string",
            createdAt: "string",
            updatedAt: "string",
            locale: "string",
            contentType: {
                sys: null
            },
        },
    };

    beforeEach(async(() => {
        TestBed.configureTestingModule({
            imports: [],
            declarations: [TroubleshootingPageComponent],
            schemas: [NO_ERRORS_SCHEMA],
            providers: [{ provide: ContentfulService, useValue: contentfulServiceStub }]
        })
            .compileComponents();
    }));

    beforeEach(() => {
        fixture = TestBed.createComponent(TroubleshootingPageComponent);
        component = fixture.componentInstance;
        fixture.detectChanges();
    });

   it('should get the troubleShootingPage form Contentful', () => {
        component.getTroubleShootingPage("en-GB");
        setTimeout(() => {
            expect(component.troubleShootingPage).toEqual(troubleShootingPageMock.fields);
        }, 1000)
    });

    // I also tried:
    // it('should get the troubleShootingPage form Contentful', (done) => {
    //     component.getTroubleShootingPage("en-GB");
    //     setTimeout(() => {
    //         expect(component.troubleShootingPage).toEqual(troubleShootingPageMock.fields);
    //         done();
    //     }, 1000)
    // });
});

我用 setTimeout() 添加了一个超时,因为没有它 component.troubleShootingPage 总是 undefined,因为测试转到了 ecpect() 语句,在 getTroubleShootingPage 中的 Promise 之前() 函数已解决:

it('should get the troubleShootingPage form Contentful', () => {
            component.getTroubleShootingPage("en-GB");
            expect(component.troubleShootingPage).toEqual(troubleShootingPageMock.fields);            
});

-> 这失败了,因为 component.troubleShootingPageundefined.

我该如何解决这个问题,有什么想法吗?

好的,感谢您的评论,制作函数的提示 return promise 是必要的部分:

在组件中,我只为 return 实现了一个功能:

 getTroubleShootingPage(locale: string) {
    this.getTroubleShootingPageFromService(locale).then(page => {
      this.troubleShootingPage = page;
   })
}

getTroubleShootingPageFromService(locale: string) {
    return this.contentfulService.getTroubleShootingPage(locale);
}

在我的测试中,我现在有了这个,它工作正常:

it('should get the troubleShootingPage form Contentful', async () => {
        spyOn(contentfulServiceStub, 'getTroubleShootingPage').and.returnValue(Promise.resolve(troubleShootingPageMock))
        await component.getTroubleShootingPage("en-US");
        expect(component.troubleShootingPage).toEqual(troubleShootingPageMock);
    });