Загрузка файлов в Cypress

17 мар. 2020

Cypress — это JS-фрэймворк для End-to-End тестирования. От всех других он отличается тем, что использует не Selenium, а свой собственный движок. Это позволяет разработчикам быстрее и легче писать более надёжные тесты.

В этом посте я расскажу как добавить в Cypress кастомную команду прикрепления файлов к инпуту и покажу на примере, как загружать файлы в тест-кейсах.

Добавляем новую команду

В Cypress есть API для добавления новых и перезаписи встроенных методов. Все встроенные в Cypress методы добавлены с помощью этого же API:

Cypress.Commands.add(name, callbackFn)
Cypress.Commands.add(name, options, callbackFn)
Cypress.Commands.overwrite(name, callbackFn)

Всё, что нам нужно сделать, это добавить новую команду в cypress/support/commands.js:

Cypress.Commands.add('uploadFile', { prevSubject: true }, (subject, fixturePath, mimeType) => {
  cy.fixture(fixturePath, 'base64').then(content => {
    Cypress.Blob.base64StringToBlob(content, mimeType).then((blob) => {
      const testfile = new File([blob], fixturePath, { type: mimeType });
      const dataTransfer = new DataTransfer();
      const fileInput = subject[0];

      dataTransfer.items.add(testfile);
      fileInput.files = dataTransfer.files;

      cy.wrap(subject).trigger('change', { force: true });
    });
  });
})

Как применять

Теперь добавим новую команду для Cypress в cypress/support/commands.js:

Cypress.Commands.add('login', () => {
  Cypress.log({
    name: 'loginBySingleSignOn',
  });
  // Авторизуемся
  cy.request({
    method: 'POST',
    // Endpoint авторизации
    url: 'https://example.ru/connect/token',
    form: true,
    body: {
      // Тестовая учётка
      username: 'username',
      password: 'password',
      // Авторизуемся через grant type "password"
      grant_type: 'password',
      // Заправшиваем доступ ко всем необходимым скоупам
      scope: 'openid profile email api',
      client_id: 'spa_name',
      client_secret: 'password',
    },
  }).then((res) => {
    cy.server({
      // Добавляем в заголовок с токеном в каждый запрос
      // Не забудьте отключить автоматическую авторизацию
      // в приложение, если она у вас включена.
      // Иначе она будет перезаписывать ваш токен
      onAnyRequest: (route, proxy) => {
        proxy.xhr.setRequestHeader('Authorization', 'Bearer ' + res.body.access_token);
      },
    });

    // Переходим на главную страницу приложения
    cy.visit('<http://localhost:4200>');
  });
});

Так же не забудьте отключить встроенные в приложение методы авторизации, чтобы не перезаписывался токен и не происходили редиректы.

Как применять

Поместите файл, который вы будете загружать (например, test.jpg), в папку cypress/fixtures.

Далее в любом тестовом файле:

describe("File upload tests", () => {

  it("should upload file", () => {
    // Запускаем сервер, для контроля XHR-запросов
    cy.server();
			
    // Присваиваем запросу загрузки файлов алиас
    cy.route("POST", "/api/upload-url").as("postURL");
   
    // Переходим на страницу, где будем загружать файл
    cy.visit('localhost:4200/admin/upload-page');
	
    // Сохраняем тестовый файл и его тип в переменные
    const fixturePath = 'test.jpg';
    const mimeType = 'application/jpg';
	
    // Выбираем нужный инпут, например, по плэйсхолдеру
    // И добавляем в него файл
    cy.get('[placeholder="Файл"]').uploadFile(fixturePath, mimeType);

    // Нажимаем кнопку загрузки
    cy.get('.upload-button').click();
    
    // Ждём выполнение запроса и проверяем статус ответа
    cy.wait("@postURL").then((xhr) => {
      expect(xhr.response.body.status).to.equal(200);
    })
  })
})

Богдан Звягинцев

Спасибо за внимание! Если вы нашли ошибку или у вас есть дополнения, напишите мне в Телеграм.

© Богдан Звягинцев, 2020