Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions CHANGELOG.rst
Original file line number Diff line number Diff line change
Expand Up @@ -39,8 +39,10 @@ New Features
is met or a timeout is reached. Useful for testing asynchronous features
(like in X window environments for example).

* ``waitSignal`` and ``waitSignals`` can receive an optional callback that can
evaluate if the arguments of emitted signals should resume execution or not.
* ``waitSignal`` and ``waitSignals`` can receive an optional callback (or list of callbacks)
that can evaluate if the arguments of emitted signals should resume execution or not.
Additionally ``waitSignals`` has a new ``order`` parameter that allows to expect signals
and their arguments in a strict, semi-strict or no specific order.
Thanks `@MShekow`_ for the PR (`#141`_).

* Now which Qt binding ``pytest-qt`` will use can be configured by the ``qt_api`` config option.
Expand Down
84 changes: 84 additions & 0 deletions docs/signals.rst
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,31 @@ value of the ``raising`` parameter of the ``qtbot.waitSignal`` and
Calls which explicitly pass the ``raising`` parameter are not affected.


check_params_cb parameter
-------------------------

.. versionadded:: 2.0

If the signal has parameters you want to compare with expected values, you can pass
``check_params_cb=some_callable`` that compares the provided signal parameters to some expected parameters.
It has to match the signature of ``signal`` (just like a slot function would) and return ``True`` if
parameters match, ``False`` otherwise.

.. code-block:: python

def test_status_100(status):
"""Return true if status has reached 100%."""
return status == 100

def test_status_complete(qtbot):
app = Application()

# the following raises if the worker's status signal (which has an int parameter) wasn't raised
# with value=100 within the default timeout
with qtbot.waitSignal(app.worker.status, raising=True, check_params_cb=test_status_100) as blocker:
app.worker.start()


Getting arguments of the emitted signal
---------------------------------------

Expand Down Expand Up @@ -110,6 +135,65 @@ the ``raising`` parameter::
# signal or a qtbot.SignalTimeoutError will be raised
assert_application_results(app)

check_params_cbs parameter
^^^^^^^^^^^^^^^^^^^^^^^^^^

.. versionadded:: 2.0

Corresponding to the ``check_params_cb`` parameter of ``waitSignal`` you can use the ``check_params_cbs``
parameter to check whether one or more of the provided signals are emitted with expected parameters.
Provide a list of callables, each matching the signature of the corresponding signal
in ``signals`` (just like a slot function would). Like for ``waitSignal``, each callable has to
return ``True`` if parameters match, ``False`` otherwise.
Instead of a specific callable, ``None`` can be provided, to disable parameter checking for the
corresponding signal.
If the number of callbacks doesn't match the number of signals ``ValueError`` will be raised.

The following example shows that the ``app.worker.status`` signal has to be emitted with values 50 and
100, and the ``app.worker.finished`` signal has to be emitted too (for which no signal parameter
evaluation takes place).


.. code-block:: python

def test_status_100(status):
"""Return true if status has reached 100%."""
return status == 100

def test_status_50(status):
"""Return true if status has reached 50%."""
return status == 50

def test_status_complete(qtbot):
app = Application()

signals = [app.worker.status, app.worker.status, app.worker.finished]
callbacks = [test_status_50, test_status_100, None]
with qtbot.waitSignals(signals, raising=True, check_params_cbs=callbacks) as blocker:
app.worker.start()


order parameter
^^^^^^^^^^^^^^^^^^^^^

.. versionadded:: 2.0

By default a test using ``qtbot.waitSignals`` completes successfully if *all* signals in ``signals``
are emitted, irrespective of their exact order. The ``order`` parameter can be set to ``"strict"``
to enforce strict signal order.
Exemplary, this means that ``blocker.signal_triggered`` will be ``False`` if ``waitSignals`` expects
the signals ``[a, b]`` but the sender emitted signals ``[a, a, b]``.

.. note::

The tested component can still emit signals unknown to the blocker. E.g.
``blocker.waitSignals([a, b], raising=True, order="strict")`` won't raise if the signal-sender
emits signals ``[a, c, b]``, as ``c`` is not part of the observed signals.

A third option is to set ``order="simple"`` which is like "strict", but signals may be emitted
in-between the provided ones, e.g. if the expected signals are ``[a, b, c]`` and the sender
actually emits ``[a, a, b, a, c]``, the test completes successfully (it would fail with ``order="strict"``).

Making sure a given signal is not emitted
-----------------------------------------

Expand Down