Helphin
Helphin

Reputation: 183

How to write the unit testing for the file upload method in the Angular 7 (or 2+)

I'm trying to write the unit testing for the file upload method in the angular 7. Getting the below error in the testing window. I'm new for angular unit testing. Could someone help, How to add mock files to get the full code coverage?

TypeError: Cannot set property 'value' of undefined

Here is my unit test code (spec file),

describe('ImportComponent', () => {
    let component: ImportComponent;
    let fixture: ComponentFixture<ImportComponent>;
    let element;

    beforeEach(
        async(() => {
            TestBed.configureTestingModule({
                imports: [ HttpClientModule, RouterTestingModule ],
                declarations: [ ImportComponent ]
            }).compileComponents();
        })
    );

    beforeEach(() => {
        fixture = TestBed.createComponent(ImportComponent);
        component = fixture.componentInstance;
        element = fixture.nativeElement;
        fixture.detectChanges();
    });

    it('should create', () => {
        expect(component).toBeTruthy();
    });

    it('should upload the file', () => {
        component.importFile();
        const inputEl = element.querySelector('#postal_file');
        const fileList = { 0: { name: 'foo', size: 500001 } };
        inputEl.value = {
            target: {
                files: fileList
            }
        };
        inputEl.dispatchEvent(new Event('change'));     
    });
});

Method in the component

importFile() {
        const inputEl: HTMLInputElement = this.el.nativeElement.querySelector('#postal_file');
        const fileCount: number = inputEl.files.length;
        const formData = new FormData();
        if (fileCount > 0) {
            formData.append(this.postalFileName, inputEl.files.item(0));
            this.postalService.importPostalCodes(formData).subscribe((data) => {
                this.result = data;
            });
        }
    }

and the HTML,

<div class="file-import">
        <form action="" method="post" encType="multipart/form-data">
            <label for="postal_file">Choose File</label>
            <input type="file" name="postal_file" id="postal_file">
            <button type="button" (click)="importFile()">Import</button>
        </form>
    </div>

The unit test is not covered all the code as shown in the below image, please help , how to ge the 100% code coverage.

Code coverage image

Upvotes: 16

Views: 28373

Answers (2)

Adrita Sharma
Adrita Sharma

Reputation: 22203

A simple way to test file upload and check model value set.

.html

<input (change)="onFileSelected()" #fileInput type="file" id="file">

.ts

uploadedFile : any

onFileSelected() {
  const inputNode: any = document.querySelector('#file');
  this.uploadedFile  = inputNode.files[0];
}

spec.ts

it('should detect file input change and set uploadedFile  model', () => {
    const dataTransfer = new DataTransfer()
    dataTransfer.items.add(new File([''], 'test-file.pdf'))

    const inputDebugEl  = fixture.debugElement.query(By.css('input[type=file]'));
    inputDebugEl.nativeElement.files = dataTransfer.files;

    inputDebugEl.nativeElement.dispatchEvent(new InputEvent('change'));

    fixture.detectChanges();

    expect(component.uploadedFile).toBeTruthy()
    expect(component.uploadedFile).toBe('test-file.pdf')
    
});

it('file change event should arrive in handler', () => {
    const element = fixture.nativeElement;
    const input = element.querySelector('#file');
    spyOn(component, 'onFileSelected');
    input.dispatchEvent(new Event('change'));
    fixture.detectChanges();
    expect(component.onFileSelected).toHaveBeenCalled();
});

Upvotes: 25

Helphin
Helphin

Reputation: 183

For the 100% code coverage of the mentioned section, I have added below 2 test cases. This works for me.

it('should upload the file - checkFileExist = true', () => {
    spyOn(component, 'checkFileExist').and.returnValue(true);
    spyOn(postalService,'importPostalCodes').and.callThrough();
    component.importFile();
    expect(postalService.importPostalCodes).toHaveBeenCalled();
});

it('should upload the file - checkFileExist = false', () => {
    spyOn(component, 'checkFileExist').and.returnValue(false);
    spyOn(postalService,'importPostalCodes').and.callThrough();
    component.importFile();
    expect(postalService.importPostalCodes).toHaveBeenCalledTimes(0);
});

Upvotes: 2

Related Questions