How to test input file with Jest and vue/test-utils

10,875

Solution 1

You could do this using the DataTransfer object. Unfortunately, it hasn't been added to JSDOM, so you can't test in Jest. There's an open issue to add the object—https://github.com/jsdom/jsdom/issues/1568

If you ran your tests in a browser using Karma, you could test like this:

const wrapper = shallow(FormComponent)
const input = wrapper.find('input[type="file"]')
const dT = new ClipboardEvent('').clipboardData || new DataTransfer()
dT.items.add(new File(['foo'], 'programmatically_created.txt'))
input.element.files = dT.files
input.trigger('change')

Solution 2

If you're just wanting to simulate a value in input.element.files and changes to input.element.value in Jest, but not necessarily accurately simulating every DOM behavior, you can do it by defining a getter/setter for those fields. This works for me:

let localImageInput
let localImageInputFiles
let localImageInputValueGet
let localImageInputValueSet
let localImageInputValue = ''

beforeEach(function() {
  localImageInput = wrapper.find('#local-image-input')
  localImageInputFilesGet = jest.fn()
  localImageInputValueGet = jest.fn().mockReturnValue(localImageInputValue)
  localImageInputValueSet = jest.fn().mockImplementation(v => {
    localImageInputValue = v
  })

  Object.defineProperty(localImageInput.element, 'files', {
    get: localImageInputFilesGet
  })

  Object.defineProperty(localImageInput.element, 'value', {
    get: localImageInputValueGet,
    set: localImageInputValueSet
  })
})

it('should do the thing', function() {
  localImageInputValue = 'some-image.gif'
  localImageInputFilesGet.mockReturnValue([{
    size: 12345,
    blob: 'some-blob',
    width: 300,
    height: 200
  }])

  localImageInput.trigger('change')

  return Vue.nextTick().then(() => {
    // Assuming the component sets input.value = '' when this event is triggered
    // and calls someFn with the image data
    expect(localImageInputValue).toEqual('')
    expect(someFn.mock.calls[0][0]).toEqual({
      size: 12345,
      blob: 'some-blob',
      width: 300,
      height: 200
    })
  })
}
Share:
10,875
J.Correa
Author by

J.Correa

Desarrollador de software. Apasionado por la programación.

Updated on July 20, 2022

Comments

  • J.Correa
    J.Correa almost 2 years

    I want to test file uploader component using Jest and vue/test-utils.

    I have this:

     describe('show progress bar of uploading file', () => {
        const wrapper = mount(FileUploaderComponent)
    
        // create csv file
        let csv = new Blob([''], { type: 'text/csv;charset=utf-8;' })
        csv.name = 'myFile.csv'
    
        let input = wrapper.find('input')
        input.element.value = csv // || csv.error value, Error here
        input.trigger('change')
    
        // Update current status
      })
    

    Where in FileUploaderComponent i have:

    <template>
      <form action="POST" enctype="multipart/form-data">
        <label class="btn btn-primary" for="input-file">
          <input class="input-file" id="input-file" name="file" type="file" accept=".xlsx, .xls, .csv">
          UPLOAD FILE
        </label>
      </form>
    </template>
    

    Throws this error:

    InvalidStateError: This input element accepts a filename, which may only be programmatically set to the empty string.

      49 |
      50 |     let input = wrapper.find('input')
    > 51 |     input.element.value = csv
      52 |     input.trigger('change')
      53 |
      54 |     // Update current status
    

    So, the question is: How can i trigger event change with file input value? in this case, a csv file as value ?

  • Vince Varga
    Vince Varga over 5 years
    any changes on this front?
  • chrismarx
    chrismarx over 5 years
    same question, I don't care about testing progress, just the ability to set a file input value
  • vedsil
    vedsil about 4 years
    Is there anything I need to import in order to use ClipboardEvent? My program throws an error that it can't find it, even though I have the npm typescript module installed.
  • vedsil
    vedsil almost 4 years
    @Anand not yet unfortunately