如何在Angular/Jasmine中测试Filereader.onload回调函数?

How can I test the Filereader.onload callback function in Angular/Jasmine?

在我的组件的 ngOnInit 中,我定义了 Filereader.onload 回调函数。我发现了几种模拟文件读取器和 onload 的解决方案,但我认为这违背了我测试调用 onload 时回调是否正确执行的目的。 所以我尝试模拟 onload 事件,然后测试回调中的函数是否被调用。

it("should import data on filereader onload event", () => {
 const fileReader = new FileReader();
      let loadEvent: ProgressEvent<FileReader>;
     
      spyOn(fileReader, "onload").and.callThrough();

      spyOn(mockServiceOne, "convertData").and.returnValue(
        mockData
      );
      spyOn(mockServiceTwo, "importData").and.callThrough();

      fileReader.onload(loadEvent);
      fixture.detectChanges();

      expect(fileReader.result).toBeDefined();

      expect(mockServiceOne.convertData).toHaveBeenCalled();
      expect(mockServiceTwo.importData).toHaveBeenCalledTimes(1);
    });
  });

我要测试的功能是这样的:

this.fileReader.onload = (event) => {
      const jsonData = JSON.parse(event.target.result.toString());
      const data = this.serviceOne.convertData(
        jsonData
      );
      this.serviceTwo.importData(data);
    };

我嘲笑了其中的两个服务和方法。但在测试规范中,他们永远不会被调用。 然而,第一个声明需要定义 onload 事件 (event.target.result) 的结果似乎是正确的。

也许将数据转换为 json 的函数的第一行有问题,因为我实际上并没有给函数一个真实的文件。但是,当我尝试提供除模拟 ProgressEvent 以外的任何内容时,它会出错。

请帮助我测试 onload 回调。我不能为此模拟 filereader onload 是否正确?

您不必嘲笑 FileReader。几天前我遇到了同样的问题。一位朋友通过描述代码的异步性质帮助我创建了一个解决方法。

将您的代码包装在 Promise 中并调用其 resolve() 回调传递 FileReader.

的结果
// you would load your file here and return the result in a Promise
readFileMethod(file: File): Promise<string> {
      return new Promise<string>((resolve) => {
            const fileReader = new FileReader();
            fileReader.onload = (event) => {
                  const jsonData = JSON.parse(event.target.result.toString());
                  const data = this.serviceOne.convertData(jsonData);
                  resolve(data);
            }
            fileReader.readAsText(); // I suppose this is what you called
      });
}

然后,您的 onInit 将如下所示:

ngOnInit(): void {
    let file; // init your file however you do
    this.readFileMethod(file).then((data) => {
        this.serviceTwo.importData(data);
    });
}

要测试新方法,请在成功回调中使用 waitForAsyncexpect()

it('should do whatever with the file', waitForAsync(() => {
    component.readFileMethod(file).then((data) => {
        expect(); // your test here
    });
}));

要测试您的 onInit,请使用 fakeAsync()tick():

it('should do whatever with the file', fakeAsync(() => {
    spyOn(mockServiceOne, "convertData").and.returnValue(
        mockData
    );
    spyOn(mockServiceTwo, "importData").and.callThrough();

    fixture.detectChanges();
    tick();
    expect(mockServiceOne.convertData).toHaveBeenCalled();
    expect(mockServiceTwo.importData).toHaveBeenCalledTimes(1);
}));