From 9024a4c6cf4766510b9449f5437526c9056d0c6a Mon Sep 17 00:00:00 2001 From: detachhead Date: Sun, 30 Jun 2024 19:21:57 +1000 Subject: [PATCH 1/3] fix variable name in comment --- pytest_robotframework/_internal/pytest/plugin.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pytest_robotframework/_internal/pytest/plugin.py b/pytest_robotframework/_internal/pytest/plugin.py index 1daec0cc..387f9322 100644 --- a/pytest_robotframework/_internal/pytest/plugin.py +++ b/pytest_robotframework/_internal/pytest/plugin.py @@ -350,7 +350,7 @@ def _robot_run_tests(session: Session, xdist_item: Item | None = None): "listener": listeners, }, ) - # if item_context is not set then it's being run from pytest_runtest_protocol instead of + # if xdist_item is not set then it's being run from pytest_runtest_protocol instead of # pytest_runtestloop so we don't need to re-implement pytest_runtest_protocol if xdist_item: robot_options = merge_robot_options( From afb6894fb1b12404b55a8d7be684b64b3e13dc8f Mon Sep 17 00:00:00 2001 From: detachhead Date: Sun, 30 Jun 2024 19:23:05 +1000 Subject: [PATCH 2/3] include skip messages in robot log --- pytest_robotframework/_internal/robot/library.py | 12 +++++------- tests/test_python.py | 3 ++- 2 files changed, 7 insertions(+), 8 deletions(-) diff --git a/pytest_robotframework/_internal/robot/library.py b/pytest_robotframework/_internal/robot/library.py index b29646f7..77c1594c 100644 --- a/pytest_robotframework/_internal/robot/library.py +++ b/pytest_robotframework/_internal/robot/library.py @@ -40,13 +40,11 @@ def _call_and_report_robot_edition( if report.skipped: # empty string means xfail with no reason, None means it was not an xfail xfail_reason = report.wasxfail if hasattr(report, "wasxfail") else None - BuiltIn().skip( - # TODO: is there a reliable way to get the reason when skipped by a skip/skipif marker? - # https://github.com/DetachHead/pytest-robotframework/issues/51 - "" - if xfail_reason is None - else ("xfail" + (f": {xfail_reason}" if xfail_reason else "")) - ) + if xfail_reason is None: + skip_reason = report.longrepr[2] if isinstance(report.longrepr, tuple) else "" + else: + skip_reason = "xfail" + (f": {xfail_reason}" if xfail_reason else "") + BuiltIn().skip(skip_reason) elif report.failed: # make robot show the exception: exception = item.stash.get(exception_key, None) diff --git a/tests/test_python.py b/tests/test_python.py index d5057c2d..fb5421fe 100644 --- a/tests/test_python.py +++ b/tests/test_python.py @@ -36,7 +36,8 @@ def test_one_test_skipped(pr: PytestRobotTester): pr.run_and_assert_result(skipped=1) pr.assert_log_file_exists() assert output_xml().xpath( - "./suite//test[@name='test_one_test_skipped']/kw[@type='SETUP']/msg[@level='SKIP']" + "./suite//test[@name='test_one_test_skipped']/kw[@type='SETUP']/msg[@level='SKIP' and " + + ".='Skipped: foo']" ) From 9a39fa95c3e8d249efa7c35db69db8bd8afbc586 Mon Sep 17 00:00:00 2001 From: detachhead Date: Sun, 30 Jun 2024 19:29:58 +1000 Subject: [PATCH 3/3] fix `--maxfail` and `--exitfirst` pytest args --- .../_internal/pytest/plugin.py | 11 +++++++++++ tests/fixtures/test_python/test_exitfirst.py | 8 ++++++++ tests/fixtures/test_python/test_maxfail.py | 12 ++++++++++++ tests/test_python.py | 18 +++++++++++++++++- 4 files changed, 48 insertions(+), 1 deletion(-) create mode 100644 tests/fixtures/test_python/test_exitfirst.py create mode 100644 tests/fixtures/test_python/test_maxfail.py diff --git a/pytest_robotframework/_internal/pytest/plugin.py b/pytest_robotframework/_internal/pytest/plugin.py index 387f9322..55b99b08 100644 --- a/pytest_robotframework/_internal/pytest/plugin.py +++ b/pytest_robotframework/_internal/pytest/plugin.py @@ -23,6 +23,7 @@ TempPathFactory, TestReport, hookimpl, + skip, version_tuple as pytest_version, ) from robot.api import logger @@ -577,6 +578,16 @@ def pytest_collect_file(parent: Collector, file_path: Path) -> Collector | None: @hookimpl(wrapper=True) def pytest_runtest_setup(item: Item) -> HookWrapperResult: + should_fail = item.session.shouldfail + if should_fail: + # this is usually handled in `pytest_runtestloop`, but since we replace it we need to + # re-implement it here. ideally it would just stop the execution entirely instead of + # skipping to match what pytest does by default, but we still want to generate a robot log + skip( + "shouldfail was set to `True`, skipping the rest of the tests" + if isinstance(should_fail, bool) + else should_fail + ) if not isinstance(item, RobotItem): # `set_variables` and `import_resource` is only supported in python files. # when running robot files, suite variables should be set using the `*** Variables ***` diff --git a/tests/fixtures/test_python/test_exitfirst.py b/tests/fixtures/test_python/test_exitfirst.py new file mode 100644 index 00000000..28273676 --- /dev/null +++ b/tests/fixtures/test_python/test_exitfirst.py @@ -0,0 +1,8 @@ +from __future__ import annotations + + +def test_foo(): + raise Exception + + +def test_bar(): ... diff --git a/tests/fixtures/test_python/test_maxfail.py b/tests/fixtures/test_python/test_maxfail.py new file mode 100644 index 00000000..237cf3e9 --- /dev/null +++ b/tests/fixtures/test_python/test_maxfail.py @@ -0,0 +1,12 @@ +from __future__ import annotations + + +def test_foo(): + raise Exception + + +def test_bar(): + raise Exception + + +def test_baz(): ... diff --git a/tests/test_python.py b/tests/test_python.py index fb5421fe..4e307fa1 100644 --- a/tests/test_python.py +++ b/tests/test_python.py @@ -7,7 +7,7 @@ from typing import TYPE_CHECKING, List, cast from _pytest.assertion.util import running_on_ci -from pytest import ExitCode, MonkeyPatch +from pytest import ExitCode, MonkeyPatch, skip from pytest_robotframework._internal.robot.utils import robot_6 from tests.conftest import ( @@ -943,3 +943,19 @@ def test_console_output(pr: PytestRobotTester): assert f"Output: {pr.pytester.path / 'output.xml'}" in result.outlines else: assert "Output: output.xml" in result.outlines + + +def test_exitfirst(pr: PytestRobotTester): + if pr.xdist: + skip( + "--exitfirst doesn't work with xdist. https://github.com/pytest-dev/pytest-xdist/issues/420" + ) + pr.run_and_assert_result("-x", failed=1, skipped=1) + + +def test_maxfail(pr: PytestRobotTester): + if pr.xdist: + skip( + "--maxfail doesn't work with xdist. https://github.com/pytest-dev/pytest-xdist/issues/868" + ) + pr.run_and_assert_result("--maxfail=2", failed=2, skipped=1)