Drag & Drop from and to File/Windows Explorer

Last edited on

Overview

It may be desirable to automate Drag & Drop from File/Windows Explorer into the AUT, or the other way around.

Unfortunately File/Windows Explorer is very unfriendly towards automation because of these points:

To overcome these problems it is possible to embed File/Windows Explorer into a custom application, such as embedded_explorer , and then automate this custom application instead.

The point of such a custom application is that it guarantees that it runs in a separate, new process (allowing Squish for Windows to hook it up in the first place), and that the right pane view is configured as desired, thus simplifying identification of objects shown in this pane.

Example

This test script demonstrates Drag & Drop from embedded_explorer into notepad.exe.

# -*- coding: utf-8 -*-

try:
    import __builtin__
except:
    import builtins as __builtin__
import os
import os.path
import subprocess
import sys


def main():
    # Must use 32-bit notepad, 64-bit variant may
    # not support drag & drop from a 32-bit application
    aut = "notepad"
    path = r"%s\SysWOW64" % os.environ["windir"]
    if not os.path.exists(path):
        path = os.environ["windir"]
    registerAUT(aut, path)
    startApplication('"' + aut + '"')

    # Ensure window activation:
    mouseClick(waitForObject({"type": "Window"}), 50, 20, MouseButton.PrimaryButton)

    drag_drop_file_on_object(squishinfo.testCase, "test.py", {"type": "Edit"})

    o = waitForObject({"type": "Edit"})
    test.verify(waitForObject({"type": "Edit"}).text.startswith("# -*- coding: utf-8 -*-"))

    return


def drag_drop_file_on_object(file_path, file_name, object_or_name):
    app_ctx_backup = currentApplicationContext()

    trg = waitForObject(object_or_name)
    trg_x = trg.x
    trg_y = trg.y

    aut = "embedded_explorer_64"
    path = squishinfo.testCase + "/.."
    registerAUT(aut, path)
    startApplication('"%s" "%s"' % (aut, file_path))
    waitForObject({"type": "ListView"})

    src = waitForObject({"text": file_name, "type": "ListViewItem", "container": {"type": "ListView"}})
    src_x = src.x
    src_y = src.y

    drag_drop_start_win(src_x + 5, src_y + 5)

    # Switch to previous application via operating
    # system - should be our notepad instance:
    nativeType("<Alt+Tab>")
    snooze(0.5)

    drag_drop_end_win(trg_x + 15, trg_y + 15)

    currentApplicationContext().detach()
    snooze(1)

    setApplicationContext(app_ctx_backup)


def drag_drop_start_win(source_x, source_y):
    # Start dragging:
    mouseMove(source_x, source_y)
    mousePress(source_x, source_y, MouseButton.PrimaryButton)

    snooze(0.5)
    for offset in range(20):
        mouseMove(source_x + offset, source_y)
        snooze(0.1)


def drag_drop_end_win(target_x, target_y):
    # Start dropping:
    snooze(0.5)
    for offset in range(-20, 1, 1):
        mouseMove(target_x + offset, target_y)
        snooze(0.1)

    snooze(0.5)
    mouseRelease(target_x, target_y, MouseButton.PrimaryButton)

    snooze(1)


def registerAUT(aut, path, quoted_args=[], squishserver_host=None, squishserver_port=None):
    binary_path = os.path.join(path, aut)
    binary_path_lower = binary_path.lower()
    if sys.platform == "win32" \
            and not binary_path_lower.endswith(".bat") \
            and not binary_path_lower.endswith(".cmd") \
            and not binary_path_lower.endswith(".jar") \
            and not os.path.exists(binary_path):
        binary_path += ".exe"
    if not os.path.exists(binary_path):
        test.fixateResultContext(1)
        try:
            test.fatal("File does not exist: %s" % binary_path)
            sys.exit(1)
        finally:
            test.restoreResultContext()
        return

    cmd = [os.path.join(os.environ["SQUISH_PREFIX"], "bin", "squishrunner")]
    if squishserver_host is not None:
        cmd.append("--host")
        cmd.append(squishserver_host)
    if squishserver_port is not None:
        cmd.append("--port")
        cmd.append("%s" % squishserver_port)
    cmd.append("--config")
    cmd.append("addAUT")
    cmd.append(aut) 
    cmd.append(path)
    test.log("Executing: %s" % repr(cmd))
    subprocess.Popen(cmd).communicate()

    args_string = quoted_args
    if __builtin__.type(args_string) != str:
        args_string = " ".join(args_string)
    aut_args = '"%s" %s' % (aut, args_string)
    return aut_args, aut, args_string, path
test.py

From within other Squish packages

If you want to move files from File/Windows Explorer on to a Qt application for example, you need to slightly modify the drag_drop*() function.

This also requires access to the Squish for Windows license component in addition to the license for the other toolkit.

You must start a server from a Squish for Windows package and start the embedded explorer on this server.

It would look this then:

def drag_drop_file_on_object(file_path, file_name, object_or_name, server_port):
    app_ctx_backup = currentApplicationContext()

    trg = waitForObject(object_or_name)
    trg_x = trg.x
    trg_y = trg.y

    aut = "embedded_explorer_64"
    path = squishinfo.testCase + "\\.."
    registerAUT(aut, path,squishserver_host="localhost", squishserver_port="{}".format(server_port))
    testSettings.setWrappersForApplication(aut, ["Windows"])
    startApplication('"%s" "%s"' % (aut, file_path), "localhost", server_port)
    waitForObject({"type": "ListView"})

    src = waitForObject({"text": file_name, "type": "ListViewItem", "container": {"type": "ListView"}})
    src_x = src.x
    src_y = src.y

    drag_drop_start_win(src_x + 5, src_y + 5)

    # Switch to previous application via operating
    # system - should be our notepad instance:
    nativeType("<Alt+Tab>")
    snooze(0.5)

    drag_drop_end_win(trg_x + 15, trg_y + 15)

    currentApplicationContext().detach()
    snooze(1)

    setApplicationContext(app_ctx_backup)
test.py