Drag & Drop from and to Windows Explorer

Last edited on

Overview

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

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

To overcome these problems it is possible to embed 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.

import __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("import __builtin__"))

    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"
    path = squishinfo.testCase + "/.."
    registerAUT(aut, path)
    startApplication('"%s" "%s"' % (aut, file_path))
    waitForObject("{type='ListView'}")

    src = waitForObject("{text='%s' type='ListViewItem' container={type='ListView'}}" % file_name)
    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