Подтвердить что ты не робот

Как вы тестируете загрузку файла с помощью Capybara и Dropzone.js?

Я перешел на использование плагина Dropzone.js для загрузки файлов с перетаскиванием. Как я могу написать тест Capybara, чтобы эта функция продолжала работать?

Раньше у меня был шаблон с элементом входного файла:

<input type="file" name="attachments">

И тест был прост:

When(/^I upload "([^"]*)"$/) do |filename|
  attach_file("attachments", File.expand_path(filename))
  # add assertion here
end

Однако это больше не работает, потому что Dropzone не имеет видимого входного файла.

4b9b3361

Ответ 1

Чтобы решить эту проблему, смоделируйте событие сброса, чтобы инициировать сброс вложения в Dropzone. Сначала добавьте эту функцию в определение шага:

    # Upload a file to Dropzone.js
    def drop_in_dropzone(file_path)
      # Generate a fake input selector
      page.execute_script <<-JS
        fakeFileInput = window.$('<input/>').attr(
          {id: 'fakeFileInput', type:'file'}
        ).appendTo('body');
      JS
      # Attach the file to the fake input selector
      attach_file("fakeFileInput", file_path)
      # Add the file to a fileList array
      page.execute_script("var fileList = [fakeFileInput.get(0).files[0]]")
      # Trigger the fake drop event
      page.execute_script <<-JS
        var e = jQuery.Event('drop', { dataTransfer : { files : [fakeFileInput.get(0).files[0]] } });
        $('.dropzone')[0].dropzone.listeners[0].events.drop(e);
      JS
    end

Затем проверьте с помощью:

    When(/^I upload "([^"]*)"$/) do |filename|
      drop_in_dropzone File.expand_path(filename)
      # add assertion here
    end

ПРИМЕЧАНИЕ. Вам необходимо загрузить jQuery, а элемент Dropzone требует класса dropzone.

Ответ 2

Построение ответа @deepwell, который мне не совсем помог, вот решение, использующее vanilla JS для событий и диспетчеризацию событий, и нейтральный селектор для dropzone:

  def drop_in_dropzone(file_path, zone_selector)
    # Generate a fake input selector
    page.execute_script <<-JS
      fakeFileInput = window.$('<input/>').attr(
        {id: 'fakeFileInput', type:'file'}
      ).appendTo('body');
    JS

    # Attach the file to the fake input selector
    attach_file("fakeFileInput", file_path)

    # Add the file to a fileList array
    page.execute_script("fileList = [fakeFileInput.get(0).files[0]]")

    # Trigger the fake drop event
    page.execute_script <<-JS
      dataTransfer = new DataTransfer()
      dataTransfer.items.add(fakeFileInput.get(0).files[0])
      testEvent = new DragEvent('drop', {bubbles:true, dataTransfer: dataTransfer })
      $('#{zone_selector}')[0].dispatchEvent(testEvent)
    JS
  end

специально использует глобальные переменные, так что я могу тестировать в консоли js, но не стесняйтесь использовать их.

Ответ 3

В случае, если кто-то заинтересован, я портировал функцию @deepwell на javascript, чтобы использовать его с салатом javascript с ароматом:

this.dropInDropzone = function(filePath) {
  var script = "fakeFileInput = $('#fakeFileInput'); if (fakeFileInput.length === 0) fakeFileInput = window.$('<input/>').attr({id: 'fakeFileInput', type:'file'}).appendTo('body');";
  // Generate a fake input selector
  return driver.executeScript(script).then(function() {
    // Attach the file to the fake input selector
    return driver.findElement(webdriver.By.css('#fakeFileInput')).sendKeys(filePath);
  }).then(function() {
    // Add the file to a fileList array
    return driver.executeScript("var fileList = [fakeFileInput.get(0).files[0]]");
  }).then(function() {
    // Trigger the fake drop event
    script = "var e = jQuery.Event('drop', { dataTransfer : { files : [fakeFileInput.get(0).files[0]] } }); $('.dropzone')[0].dropzone.listeners[0].events.drop(e);"
    return driver.executeScript(script);
  });
};