【问题标题】:How to wait for callback function in angular6+ unit test (Jasmine+karma)如何在 angular6+ 单元测试(Jasmine+karma)中等待回调函数
【发布时间】:2020-02-24 06:37:52
【问题描述】:

更新:

这似乎是 FileReader 的问题。找到这个link

谁能建议我如何为 FileReader 相关的东西编写单元测试


我有实例,我在可观察的订阅回调中有回调。

组件.ts

 public ngOnInit(): void {
 this.subscriptions.push(this.route.paramMap.subscribe((params: ParamMap) => {
 this.service.getAttachment()
      .subscribe(response => {
          this.convertBlobToBase46String(response.contentBytes, 
          async (data) => {
              this.fileData = data;
          });
        this.isAttachmentLoadingCompleted = true;
      }, error => {
        this.isAttachmentLoadingCompleted = true;
        this.loggingServie.logError(error, 'Error occurred while fetching attachment.');
      });
 }));
}

 private convertBlobToBase46String(resp, callback) {
         const reader = new FileReader();
         reader.onload = function () {
                        callback(reader.result);
                        };
         reader.readAsDataURL(resp);
    }

public isAttachmentVisible(): boolean {
       if (this.fileData != null && this.isAttachmentLoadingCompleted) {
           return true;
         }

      return false;
}

component.spec.ts

it('should hide attachment if attachment is not visible', fakeAsync(() => {
  let content = "Hello World";
  let data = new Blob([content], { type: 'text/plain' });
  let arrayOfBlob = new Array<Blob>();
  arrayOfBlob.push(data);
  let file = new File(arrayOfBlob, "Mock.svc");

  spyOn(service, 'getAttachment').and
    .returnValue(Observable.of({ mimeType: 'text/plain', contentBytes: file }));

  component.ngOnInit();
  fixture.detectChanges();
  tick(40);

  const returnValue = component.isAttachmentVisible();

  expect(returnValue).toBe(true);
  }));

这里 fileData 设置在回调函数中,并在 isAttachmentVisible() 方法中使用,因此它应该等待回调完成。但它不会等待它,即使我增加了刻度值,它也会在设置fileData之前调用isAttachmentVisible()

【问题讨论】:

    标签: angular typescript jasmine angular6 karma-jasmine


    【解决方案1】:

    ngOnInit 更改为如下,嵌套subscribes 是一种反模式。

    public ngOnInit(): void {
      this.subscriptions.push(
        this.route.paramMap.pipe(
         switchMap((params: ParamMap) => this.service.getAttachment()),
       ).subscribe(response => {
          // not sure why the callback is marked as async, nothing async about this
          this.convertBlobToBase465String(response.contentBytes, async data => {
            this.fileData = data;
            // see the bottom log when you run your test
            console.log(this.fileData);
          });
          this.isAttachmentLoadingCompleted = true;
       }, error => {
          this.isAttachmentLoadingCompleted = true;
          this.loggingService.logError(error, 'Error occured while fetching attachment.');
        });
      );
    }
    
    public isAttachmentVisible(): boolean {
           if (this.fileData != null && this.isAttachmentLoadingCompleted) {
               console.log('returing true for isAttachmentVisible');
               return true;
             }
    
          return false;
    }
    

    然后将您的测试更改为:

    it('should hide scanned image if image is not visible', async(done) => {
      let content = "Hello World";
      let data = new Blob([content], { type: 'text/plain' });
      let arrayOfBlob = new Array<Blob>();
      arrayOfBlob.push(data);
      let file = new File(arrayOfBlob, "Mock.svc");
    
      spyOn(service, 'getAttachment').and
        .returnValue(Observable.of({ mimeType: 'text/plain', contentBytes: file }));
    
      component.ngOnInit();
      fixture.detectChanges();
      // fixture.whenStable() waits for promises to complete, maybe you need two of these
      await fixture.whenStable();
      // await fixture.whenStable();
      console.log('fileData: ', component.fileData);
      console.log('isAttachmentLoadingCompleted: ', component.isAttachmentLoadingCompleted);
      // make sure above logs to not null and true, make them public just to see the log then
      // you can set them back to private if you would like.
      const returnValue = component.isAttachmentVisible();
    
      expect(returnValue).toBe(true);
      done();
    });
    

    【讨论】:

    • 我会试试这个。我们的代码中有多个嵌套订阅。
    【解决方案2】:

    如果您将tick() 替换为flush(),您的测试可能会按预期工作,因为callback 嵌套在subscribe() 调用中。

    flush 模拟定时器的异步时间流逝 fakeAsync 区域通过排空宏任务队列直到它为空。

    【讨论】:

    • 我也尝试过使用flush。然后它也不等待callBack
    • this.service.getAttachment()... 是否位于方法 ngOnInit 内?
    • 其实就是写在this.route.paramMap.subscribe()中。而这个订阅是用 ngOnInit() 写的
    • 您需要输入Observable&lt;ParamMap&gt; 才能触发订阅。
    • 这被触发了。回调被调用。但问题是在 ngOnInit 之后它直接检查 assert (Expect) 语句。我希望它等待回调完成。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-06-01
    • 2017-05-27
    • 1970-01-01
    • 2017-05-29
    • 2018-02-15
    • 1970-01-01
    相关资源
    最近更新 更多