pytestpytest-qt

Dialog button click in test not dismissing dialog PyQt5/pytest


When running a test that launches a dialog, the test is unable to programmatically click a button on the dialog. If I manually click the button, the test completes. Also I'm unsure why the dialog even shows at all (since I don't see the original window it was launched from).

Python 3.7.16, pytest 7.2.1

foo.py

import sys
from PyQt5 import QtCore, QtGui, QtWidgets


class Foo(QtWidgets.QWidget):

    def __init__(self):
        super().__init__()
        
        self.setupUi()

    def setupUi(self):
        self.resize(400, 200)
        
        self.button = QtWidgets.QPushButton("ClickMe")
        self.button.clicked.connect(self.launchDialog)
        
        layout = QtWidgets.QVBoxLayout()
        layout.addWidget(self.button)
        self.setLayout(layout)
        
    def launchDialog(self):
        self.dialog = FooDialog(parent=self)
        self.dialog.exec()

class FooDialog(QtWidgets.QMessageBox):
    def __init__(self, parent=None):
        super(FooDialog, self).__init__(parent)
        
        self.setWindowTitle("foo.FooDialog")
        
        self.button = QtWidgets.QPushButton("ClickMe")
        self.addButton(self.button, QtWidgets.QMessageBox.ButtonRole.ActionRole)
        

if __name__ == "__main__":
    app = QtWidgets.QApplication(sys.argv)
    foo = Foo()
    foo.show()
    sys.exit(app.exec_())

test_foo.py

import pytest, time
from pytestqt.qtbot import QtBot
from PyQt5 import QtCore

from foo import Foo


@pytest.fixture
def app(qtbot):
    foo = Foo()
    qtbot.addWidget(foo)
    return foo


def test_button(app):
    qtbot = QtBot(app)
    qtbot.mouseClick(app.button, QtCore.Qt.MouseButton.LeftButton, delay=0)
    time.sleep(2)
    qtbot.mouseClick(app.dialog.button, QtCore.Qt.MouseButton.LeftButton, delay=0)

I run the test thus:

pytest -s test_foo.py

I ran the test and expected it to complete, but instead the test hangs waiting for the button on the dialog to be clicked.


Solution

  • I worked around the problem by mocking the dialog