Satin has now ability to find a specific sub widget in widget hierarchy. Following is an example from herculeum:
def slot_with_item(name): """ Create function to determine if given QWidget has an item with specified name :param name: name of item to detect :type name: string :returns: function to check if item is found or not :rtype: function """ def matcher(widget): """ Check if widget contains item with given name :param widget: widget to check :type widget: ItemGlyph :returns: True if name matches, otherwise false :rtype: boolean """ if (widget != None and hasattr(widget, 'item') and widget.item != None and widget.item.name == name): return True else: return False return matcher ... def test_dropping_item(self): """ Test that item can be dropped """ item = (ItemBuilder() .with_name('dagger') .build()) self.character.inventory.append(item) dialog = InventoryDialog(surface_manager = self.surface_manager, character = self.character, action_factory = self.action_factory, parent = None, flags = Qt.Dialog) QTest.mouseClick(find_widget(dialog, slot_with_item('dagger')), Qt.RightButton) assert_that(self.level, does_have_item(item.name))
New function find_widget will iterate through widget hierarchy and return the first widget that satisfied given function (slot_with_item in this case). After the widget has been found, we can use QTest.mouseClick to click it and then assert that desired action has been carried out.
Advantage of this system is that I no longer have to specify exact location of the widget I’m interested clicking or otherwise manipulating. It is enough to write a function that can detect when correct widget has been found and then call find_widget. If I move a widget in another location in widget hierarchy, I don’t necessarily have to update my tests anymore.