如何使用Jest和vue / test-utils测试输入文件

时间:2018-02-26 16:42:24

标签: unit-testing vuejs2 jestjs

我想使用Jest和vue / test-utils测试文件上传器组件。

我有这个:

 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
  })

我在FileUploaderComponent中的位置:

<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>

引发此错误:

  

InvalidStateError:此输入元素接受可能的文件名   只能以编程方式设置为空字符串。

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

所以,问题是:如何用文件输入值触发事件更改?在这种情况下,csv文件为值?

2 个答案:

答案 0 :(得分:2)

您可以使用DataTransfer对象执行此操作。不幸的是,它尚未添加到JSDOM中,因此您无法在Jest中进行测试。添加对象有一个未解决的问题 - https://github.com/jsdom/jsdom/issues/1568

如果您使用Karma在浏览器中运行测试,则可以按以下方式进行测试:

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')

答案 1 :(得分:2)

如果您只想在input.element.files中模拟一个值并在Jest中更改为input.element.value,但不一定要精确模拟每个DOM行为,则可以通过为以下项定义一个getter / setter来实现这些领域。这对我有用:

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
    })
  })
}