Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to run multiple Qt Quick tests in parallel?

Tags:

c++

qt

qt-quick

Looks like Qt Quick tests require the test window to have a focus in order to send itself mouse and keyboard events. It's Ok, when I run only one test. But when I try to run multiple instances of Qt Quick tests, they fight for the window focus and this cause tests failures.

How can I perform Qt Quick tests without focusing the test window? Is there any option to force Qt Quick to use fake mouse and keyboard events instead of working with real window system? How can I run multiple instances of Qt Quick tests without focus problems?

like image 362
ivaigult Avatar asked Oct 20 '22 10:10

ivaigult


1 Answers

OK, I will bite.

You could use some C++ event posting to redirect a single event to multiple QML windows:

class Dispatcher : public QObject {
    Q_OBJECT
public slots:
    void click(qreal x, qreal y) {
        foreach (QObject * o, objects) {
            QMouseEvent * e1 = new QMouseEvent(QEvent::MouseButtonPress, QPointF(x, y), Qt::MouseButton::LeftButton, Qt::MouseButton::LeftButton, Qt::KeyboardModifier::NoModifier);
            QCoreApplication::postEvent(o, e1);
            QMouseEvent * e2 = new QMouseEvent(QEvent::MouseButtonRelease, QPointF(x, y), Qt::MouseButton::LeftButton, Qt::MouseButton::LeftButton, Qt::KeyboardModifier::NoModifier);
            QCoreApplication::postEvent(o, e2);
        }
    }
    void addTarget(QObject * obj) {
        objects.append(obj);
    }
private:
    QObjectList objects;
};

Then you create a dispatcher and register it as a context property, or register it as a QML type and instantiate it in QML if you will, and use it to register all objects that should be receiving events.

Here is the quick QML test I wrote to test if it works:

The main window contains a MouseArea which simply redirects the click event to the dispatcher. Each extra window contains a mouse area and text to output the click coordinate, and registers itself in the dispatcher. When the mouse area in the main window is clicked, a click event is simulated by the dispatcher for the two windows, and as a result the text in them confirms that the event was indeed dispatched to the window and processed by the underlying mouse area.

Window {
    id: main
    visible: true
    width: 300
    height: 300
    x: 100
    y: 100

    MouseArea {
        anchors.fill: parent
        onClicked:  Dispatcher.click(mouseX, mouseY)
    }

    Component {
        id: comp
        Item {
            anchors.fill: parent
            Text {
                id: txt
            }
            MouseArea {
                id: ma
                anchors.fill: parent
                onClicked: txt.text = "clicked at " + mouseX + ", " + mouseY
            }
        }
    }

    Window {
        id: w1
        visible: true
        width: 300
        height: 300
        x: 420
        y: 100
        Loader {
            anchors.fill: parent
            sourceComponent: comp
        }
        Component.onCompleted: Dispatcher.addTarget(w1)
    }

    Window {
        id: w2
        visible: true
        width: 300
        height: 300
        x: 740
        y: 100
        Loader {
            anchors.fill: parent
            sourceComponent: comp
        }
        Component.onCompleted: Dispatcher.addTarget(w2)
    }
}

You can use a similar approach to either redirect events from one to multiple windows, or to generate completely independent event sequences for every window, you can also write an event logger, then save events you manually trigger and play those back on at item at variable speed. You can do pretty much anything. The same approach should also work for keyboard events. Also, you can enable focus for each window at a time from the C++ side when you are posting the events.

like image 142
dtech Avatar answered Oct 21 '22 23:10

dtech