Работа с файловыми инпутами

Файловые инпуты (<input type="file">) представляют собой особый тип элементов формы, взаимодействие с которыми требует специфических подходов при тестировании компонентов во Vue.js. В Vue Test Utils работа с ними строится на симуляции событий изменения значения и правильной имитации объектов File или FileList.

Создание файлов для тестирования

Чтобы имитировать загрузку файлов, необходимо создать объекты типа File. Они представляют собой реальные файлы, которые можно передать компоненту через событие change:

const file = new File(["Hello, world!"], "example.txt", { type: "text/plain" });

Ключевые параметры:

  • Содержимое файла — массив строк или Blob.
  • Имя файла — строка, отображаемая пользователю.
  • Тип MIME — указывает тип файла, например image/png или application/pdf.

Для передачи нескольких файлов используется массив:

const files = [
  new File(["File 1 content"], "file1.txt", { type: "text/plain" }),
  new File(["File 2 content"], "file2.txt", { type: "text/plain" })
];

Симуляция изменения инпута

Файловый инпут реагирует на событие change. В Vue Test Utils его можно эмулировать через метод trigger:

const wrapper = mount(MyFileInputComponent);

const input = wrapper.find('input[type="file"]');

await input.trigger('change', {
  target: {
    files: [file]
  }
});

Обратите внимание на структуру объекта target — она должна содержать поле files, которое является массивом или объектом FileList. Vue Test Utils автоматически обновляет привязанные модели v-model или обработчики @change.

Работа с множественными файлами

Если инпут имеет атрибут multiple, тестирование нескольких файлов выглядит аналогично:

await input.trigger('change', {
  target: {
    files
  }
});

Внутри компонента files можно обрабатывать через event.target.files или через v-model.

Проверка передачи файлов в методы и обработчики

Часто требуется убедиться, что компонент корректно передает файлы в методы или API. Для этого можно использовать шпионы (jest.fn()) и проверять аргументы:

const onFileUpl oad = jest.fn();

const wrapper = mount(MyFileInputComponent, {
  props: { onFileUpload }
});

await input.trigger('change', { target: { files } });

expect(onFileUpload).toHaveBeenCalled();
expect(onFileUpload.mock.calls[0][0]).toEqual(files);

Важно сравнивать объекты File по ссылке или по ключевым свойствам (name, type, size), так как прямое сравнение объектов File иногда не срабатывает.

Асинхронная обработка файлов

Если компонент использует FileReader для чтения содержимого файла, тесты должны учитывать асинхронность:

const wrapper = mount(MyFileInputComponent);

const file = new File(["Hello"], "hello.txt", { type: "text/plain" });
const input = wrapper.find('input[type="file"]');

await input.trigger('change', { target: { files: [file] } });

// Использование nextTick для ожидания обновления состояния компонента
await wrapper.vm.$nextTick();

expect(wrapper.vm.fileContent).toBe("Hello");

Для сложных сценариев можно замокать FileReader:

jest.spyOn(window, 'FileReader').mockImplementation(() => ({
  readAsText: function(file) { this.onload({ target: { result: "Mock content" } }); },
  onload: null,
  result: null
}));

Проверка ограничений и валидации

Файловые инпуты часто имеют ограничения по типу, размеру или количеству файлов. Тестирование таких условий включает:

  • Проверку корректного фильтра файлов по MIME.
  • Проверку ограничения размера файла.
  • Проверку обработки ошибок при загрузке неподходящих файлов.

Пример проверки типа файла:

const invalidFile = new File(["data"], "file.exe", { type: "application/x-msdownload" });

await input.trigger('change', { target: { files: [invalidFile] } });

expect(wrapper.vm.error).toBe("Недопустимый тип файла");

Рекомендации по организации тестов

  • Создавать отдельные фабрики файлов для тестов, чтобы избежать дублирования.
  • Использовать await wrapper.vm.$nextTick() после изменения файлов для корректного обновления реактивных данных.
  • Мокать FileReader или API, если компонент выполняет чтение или загрузку файлов на сервер.

Файловые инпуты в Vue Test Utils требуют точной симуляции событий и структуры данных, но при соблюдении этих правил тесты становятся надежными и легко поддерживаемыми.