enthought / traitsui

TraitsUI: Traits-capable windowing framework
http://docs.enthought.com/traitsui
Other
297 stars 96 forks source link

Extend UITester support for TreeEditor #1351

Open kitchoi opened 4 years ago

kitchoi commented 4 years ago

The goal would be to extend support for downstream projects to write tests that require interacting with the GUI objects created by TreeEditor.

For the Qt part of the implementation, there are existing functions that interact with an QAbstractItemView (see https://github.com/enthought/traitsui/blob/94041ba0697cddc09fec5bcef5b462e36f4c1b55/traitsui/testing/tester/_ui_tester_registry/qt4/_interaction_helpers.py#L177), which may be reused.

Actions: (1) Look into existing tests for the editor and decide if any of the interactions are going to be useful downstream. (2) Add more tests for the editor with any new interactions that are going to be useful in downstream code as well. (3) Expand the testing support via the default target registry used by UITester. (4) Convert the existing tests for the editor to use UITester.

Optional and opportunistic: See if a test can be added for the demo using this editor (if there is one), related to #1257. It might also provide motivation as to what features are likely useful downstream.

kozmaz87 commented 4 years ago

I am not sure if my solution could help in this. Before this testing framework came to be I had to come up with a way to system test from UI all the way. I used pytest-qt to manipulate the view using Qt API and for sake of simplicity I created a pytest fixture to navigate the tree view given an item>item>item path and plugged it into pytest-bdd. In case you are looking for the Qt calls necessary for this here is mine:


@fixture()
def tree_nav_helper(qtbot, delay_ms):
    from pyface.qt import QtCore

    class TreeNavigator:

        @classmethod
        def nav_tree_items(cls, tree, item_path):
            # This generator cycles through the tree levels and returns the item at every turn
            path_steps = item_path.split('>')
            log.info(path_steps)
            current_tree = tree
            for step in path_steps:
                current_item = current_tree.findItems(step, QtCore.Qt.MatchContains | QtCore.Qt.MatchRecursive)[0]
                current_tree = current_item.treeWidget()
                yield current_item

        @classmethod
        def get_item(cls, tree, item_path):
            last_item = None
            for item in cls.nav_tree_items(tree, item_path):
                last_item = item
            return last_item

        @classmethod
        def open_item(cls, tree, item_path):
            last_item = None
            for item in cls.nav_tree_items(tree, item_path):
                last_item = item
                item.setExpanded(True)
                qtbot.wait(delay_ms)
            return last_item

        @classmethod
        def close_item(cls, tree, item_path):
            last_item = None
            for item in cls.nav_tree_items(tree, item_path):
                last_item = item
                item.setExpanded(False)
                qtbot.wait(delay_ms)
            return last_item

        @classmethod
        def click_item(cls, tree, item_path):
            item = cls.get_item(tree, item_path)
            rect = tree.visualItemRect(item)
            qtbot.mouseClick(tree.viewport(), QtCore.Qt.LeftButton, pos=rect.center())
            return item

    return TreeNavigator

This plugs in relatively well into pytest-bdd like so:

  Scenario: Check workflows
    Given the EggModel window
    When <item_path> is opened in tree
    And <item> is clicked in tree
    And <button_text> button is clicked
    Then workflow checks are successful

    Examples:
    | item_path                                | item                     | button_text |
    | Workflows>Test workflow>Compute chains   | Basic PCA                | Check       |

Enjoy.

kitchoi commented 4 years ago

@kozmaz87 Very nice! This would certainly help, thank you very much!