Saturday 29 August 2015

How to drag and drop and upload file with Selenide and JavaScriptExecutor


Demo page: http://demo.tutorialzine.com/2011/09/html5-file-upload-jquery-php/

This page contains drag and drop area but has no <input type='file'> tags.

So  $("#fileInput").uploadFile(file); is not working in this situation.
Drag and drop actions chain is not working too because we need to take files from user`s side.

Here is a workaround.
JavaScript part
1. Create fake input field with type="file" and other necessary attributes
2. Add it to DOM 
3. Dispatch drag and drop event
4. Remove the fake input field (optionally)

Java part
1. prepare files
2. execute javascript to get new input field
3. use $("#fileInput").uploadFile(file);   from Selenide to send file
4. execute javascript to dispatch drag and drop event

  

public class DragAndDropFilesTest{


    @Test

    public void testUserCanDragAndDropFiles() {
        open("http://demo.tutorialzine.com/2011/09/html5-file-upload-jquery-php/");

        // prepare files

        ArrayList<File> files = new ArrayList<File> ();
        files.add(new File("/path/to/file/file1.png"));
        files.add(new File("/path/to/file/file2.png"));

        // drag and drop area

        SelenideElement dragTarget = $("#dropbox");

        // drag and drop the 1st file

        
        dragAndDropFile(files.get(0), dragTarget);
        // drag and drop the 2nd file
        //  it might be necessary to wait for uploaded files appearing on the page. Css selector ".uploaded"         
        dragAndDropFile(files.get(1), dragTarget, ".uploaded");

        assertEquals($$(".uploaded").size(), files.size(), "Not all files are attached");



    }


    public void dragAndDropFile(File file, SelenideElement dragTarget) {

    /*
    *    Usage:
    *    dragAndDropFile(files.get(0), $("#dragAndDropAreaId");
    *
    */
        createInputFile();
        SelenideElement fileInput = $("#selenideUpload");
        fileInput.uploadFile(file);

        dispatchFileDragAndDropEvent("dragenter", "document", fileInput);

        dispatchFileDragAndDropEvent("dragover", "document", fileInput);
        dispatchFileDragAndDropEvent("drop", dragTarget, fileInput);

        // remove fake input file element

        executeJavaScript("arguments[0].parentNode.removeChild(arguments[0]);", fileInput);
    }

    public void dragAndDropFile(File file, SelenideElement dragTarget, String waitForCss ) {

    /*
    *    Usage:
    *    dragAndDropFile(files.get(0), $("#dragAndDropAreaId", ".uploaded");
    *
    */
        createInputFile();
        SelenideElement fileInput = $("#selenideUpload");
        fileInput.uploadFile(file);

        dispatchFileDragAndDropEvent("dragenter", "document", fileInput);

        dispatchFileDragAndDropEvent("dragover", "document", fileInput);
        dispatchFileDragAndDropEvent("drop", dragTarget, fileInput);
        $(waitForCss).waitUntil(appears, 5000); // wait until file appears on the page
        // remove fake input file element
        executeJavaScript("arguments[0].parentNode.removeChild(arguments[0]);", fileInput);
    }

    public void dragAndDrop(SelenideElement fileInput, SelenideElement dragTarget) {

    /*
    *         Usage:
    *
    *         // upload the first file
    *        createInputFile();
    *        SelenideElement fileInput = $("#selenideUpload");
    *        fileInput.uploadFile(files.get(0));
    *
    *        // upload the second file
    *        createInputFile();
    *        SelenideElement fileInput = $("#selenideUpload");
    *        fileInput.uploadFile(files.get(1));
    *
    */
        dispatchFileDragAndDropEvent("dragenter", "document", fileInput);
        dispatchFileDragAndDropEvent("dragover", "document", fileInput);
        dispatchFileDragAndDropEvent("drop", dragTarget, fileInput);
        $(".uploaded").waitUntil(appears, 5000); // wait until file appears on the page
        executeJavaScript("arguments[0].parentNode.removeChild(arguments[0]);", fileInput);
    }

    public void createInputFile() {

        // Generate a fake input file selector
        executeJavaScript("var input = document.createElement('input');" +
                "input.id = 'selenideUpload';" +
                "input.type = 'file';" +
                "input.style.display = 'block';" +
                "input.style.opacity = '1';" +
                "input.style['transform']='translate(0px, 0px) scale(1)';" +
                "input.style['MozTransform']='translate(0px, 0px) scale(1)';" +
                "input.style['WebkitTransform']='translate(0px, 0px) scale(1)';" +
                "input.style['msTransform']='translate(0px, 0px) scale(1)';" +
                "input.style['OTransform']='translate(0px, 0px) scale(1)';" +
                "input.style.visibility = 'visible';" +
                "input.style.height = '1px';" +
                "input.style.width = '1px';" +
                "input.name = 'uploadfile';" +
                "if (document.body.childElementCount > 0) {" +
                "document.body.insertBefore(input, document.body.childNodes[0]);" +
                "} else {" +
                "document.body.appendChild(input);" +
                "}");

    }


    public void dispatchFileDragAndDropEvent(String eventName, Object to, SelenideElement fileInputId){

    String script =  "var files = arguments[0].files;" +
            "var items = [];" +
            "var types = [];" +
            "for (var i = 0; i < files.length; i++) {" +
            " items[i] = {kind: 'file', type: files[i].type};" +
            " types[i] = 'Files';" +
            "}" +
            "var event = document.createEvent('CustomEvent');" +
            "event.initCustomEvent(arguments[1], true, true, 0);" +
            "event.dataTransfer = {" +
            " files: files," +
            " items: items," +
            " types: types" +
            "};" +
            "arguments[2].dispatchEvent(event);";

        if (to instanceof String) {        // for "document" in dispatchFileDragAndDropEvent("dragenter", "document", fileInput)

            script = script.replace("arguments[2]", to.toString());
        } else {
            executeJavaScript(script,fileInputId, eventName, to);
        }

    }


}


JavaScript Source: Thanks for idea to PT024/ProfessionalTester-December2013-Herrmann.pdf

No comments:

Post a Comment