Angular - how do I test the onChange() code of a file-uploader component?

Viewed 49

I'm very new to Angular. What I am trying to acheive is write a test for an onChange() event of a file uploader component. I do not know how programmatically simulate the change event. Can I create an event (e), associate it with a DOM element and file and call onChange(e)? How do I programmatically associate a file and DOM element with an event? Or maybe I'm approaching this all wrong and I should be doing something else. Maybe the code below will make it clearer. Any help/insights would be greatly appreciated. cheers!

file-upload.html // file uploader component

<div class="input-group input-group-sm mb-3">
    <div class="custom-file">
        <input type="file" class="custom-file-input" id="inputGroupFile01"
            (change)="onChange($event)" formControlName="file" accept=".csv,.xlsx">
        <label #chooseFileText class="custom-file-label" for="inputGroupFile01"></label>
    </div>
</div>

file-upload.ts // code to be tested

onChange(event) {
    this.file = event.target.files[0];
    if (this.file != null) {
      this.chooseFileText.nativeElement.innerHTML = this.file.name;
    } else {
      this.chooseFileText.nativeElement.innerHTML = "";
    }
}

file-upload.spec.ts // test fixture

it('should call onChange', () => {
    const e = new Event('');
    // How d I associate e with the DOM element? 
    component.file = new File(['foo', 'bar'], 'foobar.csv');
    // how do I set the file above with e?
    component.onChange(e);
    //  Expect the following conditions below:  
    //          component.chooseFileText.nativeElement.innerHTML = component.file.name; (if component.file is null)
    //          component.chooseFileText.nativeElement.innerHTML = ""; (if component.file is null)
});
1 Answers

In some ways this is an opinion-based question because, in my opinion, DOM-based testing as you are attempting to do is more appropriate for E2E testing rather than unit testing.

As you've stated, you are attempting to test the function itself.

Again, in my opinion, your test name should be about expectation. We already know that onChange will get called because you are calling it in the test.

So:

it('should correctly change display onChange', () => {
  let e = { "target": { "files": [{"name": "file1"}]}};
  component.onChange(e);

  expect(component.chooseFileText.nativeElement.innerHTML).toEqual('file1');
 
  e = { "target": { "files": null}};
  component.onChange(e);
 
 expect(component.chooseFileText.nativeElement.innerHTML).toEqual('');
  
}

Here is a working stackblitz which kind of illustrates it in action.

What you will find is null is not handled properly by your code in its current state.

Related