8

I want to test file upload, by dragging file to the drop zone in the page, however I can't find a way to simulate file dragging from the desktop folder. The only way I managed to found is the following one -

desktop.browser.actions().dragAndDrop(elem,target).mouseUp().perform();(Protractor)

However as far as I can understand, it drags only css element.

2 Answers 2

12

This is a working example to simulate a file drop from the desktop to a drop area:

const dropFile = require("./drop-file.js");
const EC = protractor.ExpectedConditions;

browser.ignoreSynchronization = true;

describe('Upload tests', function() {

  it('should drop a file to a drop area', function() {

    browser.get('http://html5demos.com/file-api');

    // drop an image file on the drop area
    dropFile($("#holder"), "./image.png");

    // wait for the droped image to be displayed in the drop area
    browser.wait(EC.presenceOf($("#holder[style*='data:image']")));
  });

});

The content of drop-file.js :

var fs = require('fs');
var path = require('path');

var JS_BIND_INPUT = function (target) {
  var input = document.createElement('input');
  input.type = 'file';
  input.style.display = 'none';
  input.addEventListener('change', function () {
    target.scrollIntoView(true);

    var rect = target.getBoundingClientRect(),
      x = rect.left + (rect.width >> 1),
      y = rect.top + (rect.height >> 1),
      data = { files: input.files };

    ['dragenter','dragover','drop'].forEach(function (name) {
      var event = document.createEvent('MouseEvent');
      event.initMouseEvent(name, !0, !0, window, 0, 0, 0, x, y, !1, !1, !1, !1, 0, null);
      event.dataTransfer = data;
      target.dispatchEvent(event);
    });

    document.body.removeChild(input);
  }, false);

  document.body.appendChild(input);
  return input;
};


/**
 * Support function to drop a file to a drop area.
 *
 * @view
 * <div id="drop-area"></div>
 *
 * @example
 * dropFile($("#drop-area"), "./image.png");
 *
 * @param {ElementFinder} drop area
 * @param {string} file path
 */
module.exports = function (dropArea, filePath) {
  // get the full path
  filePath = path.resolve(filePath);

   // assert the file is present
  fs.accessSync(filePath, fs.F_OK);

  // resolve the drop area
  return dropArea.getWebElement().then(function (element) {

    // bind a new input to the drop area
    browser.executeScript(JS_BIND_INPUT, element).then(function (input) {

      // upload the file to the new input
      input.sendKeys(filePath);

    });
  });
};
Sign up to request clarification or add additional context in comments.

9 Comments

sheesh thats complicated
is in't this code manipulating the client html DOM, does this actually validate the real application behavior? the same code could be used to create new buttons, links or whatever we want in the test application
@PDHide, the code simulates the same events as if it were a real user. It doesn't interact with the code from the page and it doesn't check whether the page did something with those events. To validate the feature, you'll have to add some assertions from a user perspective to validate that the drop was successful (new message on the page..). For a more recent version: gist.github.com/florentbr/349b1ab024ca9f3de56e6bf8af2ac69e
@FlorentB. Document.body.append is adding to the Dom right ? Or what is it actually doing ?
Could you just explain the basic logic
|
4

You cannot drag an element from your desktop using protractor, its actions are limited to the browser capabilities.

You may have to consider dragging from the desktop to work (unless you want to test your operating system), and check that once the file is given to the HTML element, everything works correctly.

One way to achieve that is with the following:

dropElement.sendKeys(path);

For instance if that element is, as usual, an input of type file:

$('input[type="file"]').sendKeys(path);

Note that path should be the absolute path to the file you want to upload, such as /Users/me/foo/bar/myFile.json or c:\foo\bar\myFile.json.

6 Comments

You should reconsider you statement. It's possible to drop a file to a drop area with protractor alone.
@FlorentB. do you have a specific example to support the statement? Thanks.
@alex, I've done it, but I'm not going to add an example in a comment. It requires to inject a new <input> element in the page with .executeScript to obtain the file. Then send the drop event with the file attached to the drop zone once the file is uploaded with .sendKeys.
@FlorentB. I never said that drag and drop is not doable with protractor, as long as it's within the browser. What is not possible is to emulate a drag and drop from a desktop file - on the host computer - into the browser window. We can only simulate the behavior that happens on the browser, using sendKeys as you said, which happens to be my answer as well.
@floribon, It is possible to emulate a drag and drop from a desktop file, on the host computer, into the browser's window with protractor. Usually a drop area is a simple div without an input. So all it takes to simulate the drop is to send the dragenter, dragover and drop events to the div with the file define in dataTransfer. So a simple dropElement.sendKeys(path); or $('input[type="file"]').sendKeys(path); is not going to work. See by yourself and try to drop a file in this example: html5demos.com/file-api
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.