Fake file drop event for unit testing
Asked Answered
F

2

5

I'm trying to simulate a file Drop event for testing an angular directive but I cannot manage to create the DragEvent.

it('should output file drop when file droped', () => {
    const file = new File([''], 'dummy.txt'); // got my file right there, want to drop it on "des"
    des.dispatchEvent(new DragEvent('drop', { dataTransfer: { items: [ new DataTransferItem(file)] } }));
    // ...
});

I'm unsure what to do with the second parameter to have my file in there..

Flexor answered 17/7, 2019 at 16:47 Comment(0)
R
9

Not sure if this is still relevant but I had this issue today and solved it. Just leaving this here incase someone else has the same issue.

This is the method I was attempting to test inside the directive

@HostListener('drop', ['$event'])
onDrop(evt: any) {
    evt.preventDefault()
    evt.stopPropagation()
    this.fileOver = false
    const files = evt.dataTransfer.files
    if (files.length > 0) {
        this.fileDropped.emit(files)
    }
}

I created the test suite as per Angulars documentation, creating a fake component with the directive added to a div element.

@Component({
  template: `<div id="file-drop-area" filedrop (fileDropped)="handleDrop($event)"></div>`
})
class TestFileDropComponent {
    handleDrop(files: FileList) {}
}

describe('FileDropDirective', () => {
    let directive: FileDropDirective
    let component: TestFileDropComponent
    let fixture: ComponentFixture<TestFileDropComponent>;
    beforeEach(async () => {
        await TestBed.configureTestingModule({
          declarations: [ TestFileDropComponent, FileDropDirective ]
        })
        .compileComponents();
     });

     beforeEach(() => {
         fixture = TestBed.createComponent(TestFileDropComponent);
         component = fixture.componentInstance

         fixture.detectChanges();
     })
})

Then I created a new DataTransfer instance, pushed my fake file to the items array and passed the DataTransfer instance to the event which was then dispatched.

    it('should verify the directive recognises a drop event', () => {
        spyOn(component, 'handleDrop')

        const el: HTMLElement = fixture.nativeElement
        const fileDropArea: HTMLDivElement = el.querySelector('#file-drop-area')!
        const file = new File([''], 'dummy.txt')
        
        const dataTransfer = new DataTransfer()
        dataTransfer.items.add(file)

        const event = new DragEvent("drop", { dataTransfer })
        fileDropArea.dispatchEvent(event)
        fixture.detectChanges()
        
        expect(component['handleDrop']).toHaveBeenCalledWith(dataTransfer.files)
    })
Rileyrilievo answered 25/5, 2022 at 13:26 Comment(1)
IMO this should be marked as the answer for the question.Denisse
F
4

I ended up dividing the tests in 2 parts:

First the drop

it('should call onFileDrop when there is a drop event', () => {
    spyOn(directive, 'onFileDrop');
    dest.triggerEventHandler('drop', new DragEvent('drop'));
    expect(directive.onFileDrop).toHaveBeenCalled();
});

Then the handling in the function

it('should output the files that when onFileDrop is called', () => {
    spyOn(directive.fileDrop, 'emit').and.callThrough();
    const file = new File([''], 'dummy.jpg');
    const fileDropEvent = { preventDefault: () => {}, dataTransfer: { files: [file, file, file] }};
    let outputFiles;

    directive.fileDrop.pipe(first()).subscribe(f => outputFiles = f);
    directive.onFileDrop(fileDropEvent);
    expect(directive.fileDrop.emit).toHaveBeenCalled();
    expect(outputFiles.length).toBe(3);
    expect(outputFiles[0]).toBe(file);
});
Flexor answered 18/7, 2019 at 11:29 Comment(3)
What exactly is directive?Devonne
What is dest?Eriha
@Eriha this was made 3 years ago I don't recallFlexor

© 2022 - 2024 — McMap. All rights reserved.