如何在Vitest中用Vue Test Utils模拟input[type=file]文件选择
解决Vitest中模拟input[type=file]文件选择时的files属性赋值错误问题
问题出在input[type=file]的files属性是只读属性,无法直接通过赋值语句修改,所以原代码中await fileInput.element.files = [mockFile]会抛出属性无效的错误。
以下是两种可行的修正方案:
方案1:使用DataTransfer模拟文件列表
这是更贴近真实浏览器行为的方式,通过DataTransfer对象创建合法的文件列表:
import { mount } from '@vue/test-utils'; it('simulates file selection', async () => { const wrapper = mount(MyComponent); const fileInput = wrapper.find('input[type="file"]'); const mockFile = new File(['content'], 'filename.txt', { type: 'text/plain' }); // 创建DataTransfer并添加模拟文件 const dataTransfer = new DataTransfer(); dataTransfer.items.add(mockFile); // 将DataTransfer的文件列表赋值给input元素 fileInput.element.files = dataTransfer.files; await fileInput.trigger('change'); // 验证组件行为 expect(wrapper.emitted('fileSelected')).toBeTruthy(); });
方案2:通过Object.defineProperty修改只读属性
如果环境不支持DataTransfer(极少情况),可以通过Object.defineProperty强制覆盖files属性:
import { mount } from '@vue/test-utils'; it('simulates file selection', async () => { const wrapper = mount(MyComponent); const fileInput = wrapper.find('input[type="file"]'); const mockFile = new File(['content'], 'filename.txt', { type: 'text/plain' }); // 覆盖只读的files属性 Object.defineProperty(fileInput.element, 'files', { value: [mockFile], configurable: true // 允许后续修改或删除该属性 }); await fileInput.trigger('change'); expect(wrapper.emitted('fileSelected')).toBeTruthy(); });
关键说明
- 两种方案都需要在修改
files属性后触发change事件,才能让组件感知到文件选择的变化。 - 优先使用方案1,因为它完全模拟了浏览器中用户选择文件的真实流程,测试结果更可靠。
内容的提问来源于stack exchange,提问作者Kartik Kodag
相关产品推荐
相关产品推荐

