Layout validation for text truncation in Qt Quick applications

Last edited on

Introduction

Application layout validation is a very difficult task no matter the test automation tool. Some level of layout validation can be achieved even using tools which verify object properties and don't rely on screenshot comparison. For Qt Quick applications it can be done by analyzing the implicitWidth and implicitHeight properties of Qt Quick Text items. These properties hold the natural size of the item if no width or height is specified.

Solution

This article presents a JavaScript solution. Similar solutions can be implemented in other scripting languages supported by Squish. We'll start by implementing a function, which returns true if the current size of the given item isn't less than the values in the implicitWidth and implicitHeight properties.

function isSufficientlySized(obj) {
    return (!(typeof obj.implicitWidth === 'undefined')
            && !(typeof obj.implicitHeight === 'undefined')
            && obj.width >= obj.implicitWidth && obj.height >= obj.implicitHeight);
}

Next, we'll define a wrapper for above function, which calls the Squish API functions test.pass or test.fail depending on the isSufficientlySized result. This allows us to check the Squish Results for which items were analyzed and the outcome of the analysis.

function verifySize(obj) {
    var name = objectMap.symbolicName(obj);
    if ( isSufficientlySized(obj) ) {
        test.pass("Sufficient size of " + name);
        return true;
    } else {
        test.fail("Insufficient size of " + name);
        return false;
    }
}

Next we'll create a function which generates a list of all items contained in the given frame or window. Function fetchAllItems(obj) recursively traverses all visible items with a text property whose obj is an ancestor.

function fetchAllItems(obj)
{
    var children = object.children(obj);
    var items = [];

    if (obj.visible && !(typeof obj.text === 'undefined'))
        items.push(obj);

    for (var i in children) {
        var child = children[i];
        items = items.concat(fetchAllItems(child));
    }
    return items;
}

Finally, we'll implement the verifyDialogLayout(dlg, output) function, which is called directly from the test case. It takes two arguments: main item object reference (frame,window) and image filename, where the screenshot of the main item is stored in the event the case validation for correct layout is not a positive value. All text items whose size are not sufficient will be drawn in red on the captured screenshot. This is done setting the color property.

function verifyDialogLayout(dlg, output) {

    var items = fetchAllItems(dlg);

    var ok = true;
    for (var i in items) {
        var w = items[i];

        if (!verifySize(w)) {
            ok = false;

            if (!(typeof w.color === 'undefined')) {
                w.color = "red";
            }
        }
    }
    if (!ok) {
        var pix = grabWidget(dlg);

        // Save image on the computer where the application is running.
        // (Use object.grabScreenshot() to have the image on the
        // computer where the Squish IDE (or squishrunner) is being
        // executed. See https://doc.qt.io/squish/squish-api.html#object-grabscreenshot-function)
        pix.save(output);

        test.log("Wrote illustration to " + output);
    }
}

Example

To present this solution in action we use the Qt Quick application AddressBook. First, we need to make some items smaller than they should be. To do that we implement function messWithSizes(), which sets incorrect size for some items.

function messWithSizes()
{
    var button = waitForObject(names.About_Text);
    button.width = 18;
    button.clip = true;
    var name = waitForObject(names.editView_FirstName_Text);
    name.width = 30;
    name.clip = true;
    var field = waitForObject(names.editView_firstNameField_TextField);
    field.height = 17;
    field.clip = true;
}

function main() {
    startApplication("quickaddressbook");

    mouseClick(waitForObject(names.Add_BasicButton), 25, 14, Qt.LeftButton);
    type(waitForObject(names.editView_firstNameField_TextField), "MyName");
    messWithSizes();
    verifyDialogLayout(waitForObject(names.QQuickWindowQmlImpl), "layout_checkQtQuick.png");
}
Squish IDE: Test Results View

Additionally, the screenshot was generated with failed widgets marked as follows: