Загрузка файлов может осуществляться различными способами, но все они имеют несколько общих черт. Прежде всего, при загрузке файлов необходимо иметь фронтенд, готовый принять файл, а затем бэкенд, готовый обработать файл. Начнем с фронтенда и с того, как можно выполнить загрузку с помощью Cypress.
Содержание:
Подпишитесь на наш ТЕЛЕГРАМ КАНАЛ ПО АВТОМАТИЗАЦИИ ТЕСТИРОВАНИЯ
Загрузка файла с помощью Cypress
Начиная с версии 9.3.0, в Cypress появилась команда .selectFile(), которая может обрабатывать все необходимые загрузки файлов. Ее использование очень просто:
cy.get('#upload')
.selectFile('cypress/fixtures/logo.png')
Итак, здесь немного углубимся в код. Каждый раз, когда вы выполняете загрузку, на странице присутствует элемент <input type=file>. Даже если вы его не видите, он там есть. Это элемент HTML5, который предоставляет API вашему приложению, чтобы взаимодействовать с браузером и открывать окно «Выбрать файл». Данный элемент обычно отображается на странице следующим образом:

Однако, когда нам нужно загрузить файл с помощью Cypress, мы не нажимаем на эту кнопку, а выбираем элемент <input> и используем для него функцию .selectFile(). Таким образом, вместо того чтобы взаимодействовать с диалоговым окном для выбора файла, мы просто указываем путь к файлу, который хотим загрузить. Но что делать, если кнопки «Выбрать файл» не видно, а вместо нее есть кнопка загрузки или область перетаскивания?
Загрузка через область перетаскивания
Многие страницы имеют более приятный пользовательский интерфейс, в котором клиент может просто перетащить файл или нажать на красиво оформленную кнопку. Это может выглядеть примерно так:

В подобных случаях элемент <input> часто оказывается скрытым. Интересно то, что элемент <input> можно найти в странных местах в DOM, часто далеко от области перетаскивания. Это происходит потому, что JavaScript обрабатывает вставку файла. Можно представить себе, что файл берется из области перетаскивания и передается в элемент <input>, где он и обрабатывается.
В проекте Trelloapp область перетаскивания выглядит примерно так:

Видно, что элемент <input> имеет стиль display: none и поэтому скрыт от пользователя. Для загрузки файла в эту область перетаскивания можно выбрать одну из трех стратегий:
// input is invisible, so we need to skip Cypress UI checks
cy.get('input[type=file]')
.selectFile('cypress/fixtures/logo.png', { force: true })
// make our input visible by invoking a jQuery function to it
cy.get('input[type=file]')
.invoke('show')
.selectFile('cypress/fixtures/logo.png')
// use Cypress’ abilty to handle dropzones
cy.get('[data-cy=upload-image]')
.selectFile('cypress/fixtures/logo.png', { action: 'drag-drop' })
Обратите внимание на то, что в третьем примере выбирается вся область перетаскивания, вместо того, чтобы выделять элемент <input>. Это важно, поскольку существует разница между использованием этих двух стратегий. Если бы мы выбрали не тот элемент, то могли бы получить сообщение типа: cy.selectFile() cy.selectFile() can only be called on an <input type="file"> or a <label for="fileInput"> pointing to or containing one.
Загрузка через API
Еще один способ – это отправка изображения на сервер. Фронтенд может обрабатывать загрузку изображения различными способами, поэтому в вашем приложении могут быть небольшие отличия в обработке загрузки файлов, но общая идея выглядит примерно так:
cy.fixture('logo.png', 'binary').then( image => {
const blob = Cypress.Blob.binaryStringToBlob(image, 'image/png');
const formData = new FormData();
formData.append('image', blob, 'logo.png');
cy.request({
method: 'POST',
url: '/api/upload',
body: formData,
headers: {
'content-type': 'multipart/form-data'
},
})
})
Теперь разберемся с этим подробнее. Элемент <input type=file> обычно является частью <form> в html. Как правило, элемент <form> содержит несколько элементов <input>. Перед передачей в API они обрабатываются интерфейсом FormData. По сути, каждый элемент данных добавляется к объекту FormData и затем отправляется на сервер с помощью API.
В Cypress необходимо вручную создать этот объект FormData и добавить в него изображение. А также, перед добавлением с помощью метода .append() изображения к объекту FormData, нужно обработать его. Это достигается двумя способами:
- изображение нужно загрузить как фикстуру, с использованием двоичного,
binary, кодирования - это двоично закодированное изображение необходимо преобразовать в тип данных Blob
Blob означает «Двоичный большой объект» – другими словами, мы преобразуем наше изображение в текст. Обычно этим занимается фронтенд-часть приложения. Причина, по которой в Cypress тесте нужно делать это вручную, заключается в том, что мы избегаем использования фронтенда.
После обработки файла и заполнения объекта FormData, можно вызывать API. В качестве body запроса будет выступать сам объект FormData. Единственная дополнительная деталь – это добавление заголовка 'content-type': 'multipart/form-data', чтобы сервер знал, что мы посылаем запрос такого типа.
Как уже упоминалось, окончательное решение по загрузке файла через API будет зависеть от самого API и тестируемого приложения, но общая идея должна оставаться примерно такой же, как в приведенном выше примере.
Перевод статьи «Cypress basics: Uploading a file».
Пингбэк: Большой учебник по Cypress