Angular & Jasmine Unit Test change event for input[type=“file”]

◇◆丶佛笑我妖孽 提交于 2019-12-01 19:53:28

Let's follow the divide and conquer rule - since the aim of Unit Test is to test the parts of component logic separately, I would slightly change the component logic in order to make it easier to Unit Test.

You're setting the anonymous callback function for onload inside your onUploadFile method, so there is no way to spyOn it. As a trade off - you can refactor out the callback method:

export class TestComponent {
  ...
  getLoadCallback(fg: FormGroup, file: File, reader: FileReader): () => void {
    return () => {
      fg.patchValue({
        filename: file.name,
        filetype: file.type,
        value: reader.result.split(',')[1],
        dateUploaded: new Date()
      });

      // do some other stuff here
    };
  }

  onUploadFile(evt: Event, index: number, isReq: boolean = false): void {
    const reader = new FileReader();
    const target = <HTMLInputElement>evt.target;

    if (target.files && target.files.length) {
      const file = target.files[0];
      reader.readAsDataURL(file);
      const fg = this.getUploadFormGroup(index, isReq);
      reader.onload = this.getLoadCallback(fg, file, reader);
    }
  }
  ...
}

So, now we can create at least three Unit Tests: one for triggering onUploadFile on input event (your existing test is good for this), another one for testing getLoadCallback method and lastly - for onUploadFile method:

  it('getLoadCallback', () => {
    const mockValue = ['a', 'b'];
    const result = jasmine.createSpyObj('result', ['split']);
    result.split.and.callFake(() => mockValue);
    const mockReader = { result } as FileReader;
    const mockFormGroup: FormGroup = jasmine.createSpyObj('FormGroup', ['patchValue']);
    const mockFile = new File([''], 'filename', { type: 'text/html' });
    const callback: () => void = component.getLoadCallback(mockFormGroup, mockFile, mockReader);

    callback();

    const obj = {
      filename: mockFile.name,
      filetype: mockFile.type,
      value: mockValue[1],
      dateUploaded: new Date()
    }
    expect(mockFormGroup.patchValue).toHaveBeenCalledWith(obj);
  });

  it('onUploadFile', () => {
    const mockIndex = 1;
    const mockIsReq = false;
    const mockFile = new File([''], 'filename', { type: 'text/html' });
    const mockFormGroup = new FormGroup({});
    const mockEvt = { target: { files: [mockFile] } };
    const mockReader: FileReader = jasmine.createSpyObj('FileReader', ['readAsDataURL', 'onload']);
    spyOn(window as any, 'FileReader').and.returnValue(mockReader);
    spyOn(component, 'getUploadFormGroup').and.returnValue(mockFormGroup);
    spyOn(component, 'getLoadCallback').and.callThrough();

    component.onUploadFile(mockEvt as any, mockIndex, mockIsReq);

    expect((window as any).FileReader).toHaveBeenCalled();
    expect(mockReader.readAsDataURL).toHaveBeenCalledWith(mockFile);
    expect(component.getUploadFormGroup).toHaveBeenCalledWith(mockIndex, mockIsReq);
    expect(component.getLoadCallback).toHaveBeenCalledWith(mockFormGroup, mockFile, mockReader);
  });

Of course you can change mock values and create more unit tests...

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!