Angular 如何在fromEvent FileReader.loadended之后对组件进行单元测试
我试图编写一个单元测试,以断言在多步骤表单场景中表单提交后组件中的变量发生了更改。多步骤形式是功能性的,但不可单元测试。我也不知道如何调试它来确定测试失败的根本原因 给定以下功能组件方法:Angular 如何在fromEvent FileReader.loadended之后对组件进行单元测试,angular,unit-testing,rxjs,angular-forms,Angular,Unit Testing,Rxjs,Angular Forms,我试图编写一个单元测试,以断言在多步骤表单场景中表单提交后组件中的变量发生了更改。多步骤形式是功能性的,但不可单元测试。我也不知道如何调试它来确定测试失败的根本原因 给定以下功能组件方法: submitFileForm(form: NgForm): void { if (this.uploadFile) { const reader = new FileReader(); fromEvent(reader, 'error') .subscri
submitFileForm(form: NgForm): void {
if (this.uploadFile) {
const reader = new FileReader();
fromEvent(reader, 'error')
.subscribe((e: ProgressEvent) => {
console.error(e);
reader.abort();
});
fromEvent(reader, 'loadend')
.pipe(map(() => btoa(reader.result as string)))
.subscribe(() => {
// This works, but not in the test.
component.step = 1;
}, (err) => {
console.error(err);
this.step = -1;
});
reader.readAsText(this.uploadFile, 'UTF-8');
}
}
以及以下测试:
it('should go from step 0 to step 1', () => {
const mockBlob: any = new Blob([
`A,B,C\naaaa,bbb,ccc`,
], { type: 'text/csv' });
mockBlob.name = 'my.csv';
const mockFile = mockBlob as File;
component.uploadFile = mockFile;
fixture.detectChanges();
component.submitFileForm(component.fileForm);
fixture.detectChanges();
// This fails. component.step is 0. After the test is finished step is 1.
expect(component.step).toEqual(1);
}
完整示例位于,其中显示了其他详细信息。这些是角8
我试过了
将读者抽象为自己的服务。
使用NgZone.run和NgZone.runOutsideAngular包装fromEvent。
包装NgZone.run=>{component.step=1;};
将BehaviorSubject用于表单步骤。
勾选ApplicationRef。
在测试中使用fixture.whenStable。
但我认为这可能是由于对角度或区域的根本误解,以及如何正确注册角度组件的挂起任务。也可能有更好的方法来构造代码,以便以不同的方式进行单元测试。也许读者可以一直在阅读而不是等待表单提交?或者是async/await,但当与RxJS和Angular结合使用时,我对这些模式不太熟悉
我没有尝试注入ChangeDetectionRef,因为我过去在使其可测试方面遇到了麻烦
这里的ngSwitch模式可能不是最干净的,但在我看来它仍然是可能的。就我个人而言,我可能会将其分解为单独的组件,但有时我们需要遵循常见的代码样式
看起来很相似,但在这种情况下,实际的功能方面不起作用,而不是测试。
似乎没有关系。
如今,将其抽象为一项服务似乎是可行的。我可能有一些其他的副作用,但我更喜欢这种模式,它看起来更干净的组成部分。如果我浪费了任何人的时间,我很抱歉。我不会接受这个答案,因为可能有更好的答案来解释我遇到了什么
export class FileReaderService {
read(file: File): Observable<string> {
return Observable.create((observer: Observer<string>) => {
const reader = new FileReader();
reader.onerror = () => {
reader.abort();
observer.error('An error occurred reading the file.');
};
reader.onloadend = () => {
observer.next(reader.result as string);
observer.complete();
};
reader.readAsText(file, 'UTF-8');
});
}
}
测试更改:
it('should go from step 0 to step 1', () => {
const contents = `A,B,C\naaaa,bbb,ccc`;
const reader = fixture.debugElement.injector.get(FileReaderService);
spyOn(reader, 'read').and.returnValue(of(contents));
const mockBlob: any = new Blob([contents]), { type: 'text/csv' });
mockBlob.name = 'my.csv';
const mockFile = mockBlob as File;
component.uploadFile = mockFile;
fixture.detectChanges();
component.submitFileForm(component.fileForm);
fixture.detectChanges();
expect(component.step).toEqual(1);
}
我认为将FileReader抽象为一个服务,然后模拟可观察的返回将起作用。我不知道为什么在我的实际应用程序中,前几天它不起作用,但基于表单的复杂性,可能会有副作用。
it('should go from step 0 to step 1', () => {
const contents = `A,B,C\naaaa,bbb,ccc`;
const reader = fixture.debugElement.injector.get(FileReaderService);
spyOn(reader, 'read').and.returnValue(of(contents));
const mockBlob: any = new Blob([contents]), { type: 'text/csv' });
mockBlob.name = 'my.csv';
const mockFile = mockBlob as File;
component.uploadFile = mockFile;
fixture.detectChanges();
component.submitFileForm(component.fileForm);
fixture.detectChanges();
expect(component.step).toEqual(1);
}