Trigger a Javascript file drop event with Python and Selenium

I needed unit testing for a page which allows to upload files by dragging and dropping them from the desktop.

Notes

  • The target element is identified by #drag_and_drop.
  • driver is an instance of the Firefox Selenium webdriver.
  • filepath is a string, the path to a jpeg image.
  • jQuery is defined in the tested web page.
  • Tested with Firefox only.

Code example

import base64
import os

from selenium import webdriver


def drop_file(driver, filepath):
    with open(filepath, "rb") as f:
        b64 = base64.b64encode(f.read()).decode()
    filename = os.path.basename(filepath)
    mtime = str(int(os.path.getmtime(filepath)*1000))
    driver.execute_script(
        "var byte_characters = atob('"+b64+"');"
        "var byte_numbers = new Array(byte_characters.length);"
        "for (var i = 0; i < byte_characters.length; i++)"
            "byte_numbers[i] = byte_characters.charCodeAt(i);"
        "var byte_array = new Uint8Array(byte_numbers);"
        "var file = new File([byte_array],'"+filename+"', {"
            "type: 'image/jpg',"
            "lastModified: new Date("+mtime+")"
        "});"
        "var e = $.Event('drop');"
        "e.originalEvent = {dataTransfer: {files: [file]}};"
        "$('#drag_and_drop').trigger(e);"
        )

We start by encoding the file in base64 and we insert it in the script. The Javascript code will then decode the base64 string. atob() returns a string, so we must convert it first to an array of integers, then to a byte array, which we pass as a parameter to the File constructor.

Bytes → base 64 encoded string → string → array of integers → byte array.

Sources

Alexandre de Verteuil
Alexandre de Verteuil
Senior Solutions Architect

I teach people how to see the matrix metrics.
Monkeys and sunsets make me happy.

Related