Skip to content

Commit

Permalink
fix: fix handling of pytest.xfail and skipif mark
Browse files Browse the repository at this point in the history
Resolved the following issues:
	1.	Custom statuses did not work when using `pytest.xfail` within the test body. #321
	2.	The test status was displayed incorrectly when using the `skipif` mark. #320
  • Loading branch information
gibiw committed Jan 16, 2025
1 parent d1b2bd5 commit f89bbf4
Show file tree
Hide file tree
Showing 4 changed files with 66 additions and 47 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/pythonpackage.yml
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ jobs:
- "3.10"
- "3.9"
- "3.8"
- "3.7"
- "3.7.17"
changed-dir:
- "qase-api-client"
- "qase-api-v2-client"
Expand Down
9 changes: 9 additions & 0 deletions qase-pytest/changelog.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,11 @@
# qase-pytest 6.1.11

## What's new

Fixed issues with using `pytest.xfail` and the `skipif` mark:
1. Custom statuses did not work when using `pytest.xfail` within the test body.
2. The status was incorrect when using the `skipif` mark.

# qase-pytest 6.1.10

## What's new
Expand All @@ -6,6 +14,7 @@ The ability to override statuses for tests marked with the `xfail` marker has be
assigned the `skipped` status, and passed tests are assigned the `passed` status. Custom statuses can be specified by
providing the slug of the desired status in the configuration. Configuration values can be set via `qase.config.json` or
environment variables:

- `QASE_PYTEST_XFAIL_STATUS_XFAIL`
- `QASE_PYTEST_XFAIL_STATUS_XPASS`

Expand Down
2 changes: 1 addition & 1 deletion qase-pytest/pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"

[project]
name = "qase-pytest"
version = "6.1.10"
version = "6.1.11"
description = "Qase Pytest Plugin for Qase TestOps and Qase Report"
readme = "README.md"
keywords = ["qase", "pytest", "plugin", "testops", "report", "qase reporting", "test observability"]
Expand Down
100 changes: 55 additions & 45 deletions qase-pytest/src/qase/pytest/plugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -141,58 +141,68 @@ def pytest_runtest_logfinish(self):

@pytest.hookimpl(hookwrapper=True)
def pytest_runtest_makereport(self, item, call):
if not self.ignore and call.when == "call":
report = (yield).get_result()

def set_result(res):
self.runtime.result.execution.status = res

def _attach_logs():
if report.caplog:
self.add_attachments((report.caplog, "text/plain", "log.txt"))
if report.capstdout:
self.add_attachments((report.capstdout, "text/plain", "stdout.txt"))
if report.capstderr:
self.add_attachments((report.capstderr, "text/plain", "stderr.txt"))

if report.longrepr:
self.runtime.result.execution.stacktrace = report.longreprtext

if report.failed:
if call.excinfo.typename != "AssertionError":
set_result(PYTEST_TO_QASE_STATUS['BROKEN'])
else:
set_result(PYTEST_TO_QASE_STATUS['FAILED'])
self.runtime.result.add_message(call.excinfo.exconly())
elif report.skipped:
if self.__is_use_xfail_mark(report):
set_result(self.config.framework.pytest.xfail_status.xfail)
elif self.runtime.result.execution.status in (None, PYTEST_TO_QASE_STATUS['PASSED']):
set_result(PYTEST_TO_QASE_STATUS['SKIPPED'])
else:
if self.__is_use_xfail_mark(report):
set_result(self.config.framework.pytest.xfail_status.xpass)
elif self.runtime.result.execution.status is None:
set_result(PYTEST_TO_QASE_STATUS['PASSED'])

if self.reporter.config.framework.pytest.capture_logs:
_attach_logs()

# Attach the video and the trace to the test result
if hasattr(item, 'funcargs') and 'page' in item.funcargs:
page = item.funcargs['page']
if not page.video:
return
if self.ignore:
yield
return

report = (yield).get_result()

def set_result(res):
self.runtime.result.execution.status = res

def attach_logs():
logs = [
(report.caplog, "text/plain", "log.txt"),
(report.capstdout, "text/plain", "stdout.txt"),
(report.capstderr, "text/plain", "stderr.txt"),
]
for content, mime_type, filename in logs:
if content:
self.add_attachments((content, mime_type, filename))

def handle_xfail_status():
if self.__is_use_xfail_mark(report) and call.when == "call":
status = self.config.framework.pytest.xfail_status
return status.xfail if report.skipped else status.xpass
return None

if report.longrepr:
self.runtime.result.execution.stacktrace = report.longreprtext

if report.failed:
result_status = PYTEST_TO_QASE_STATUS['BROKEN'] if call.excinfo.typename != "AssertionError" else \
PYTEST_TO_QASE_STATUS['FAILED']
set_result(result_status)
self.runtime.result.add_message(call.excinfo.exconly())
elif report.skipped:
xfail_status = handle_xfail_status()
if xfail_status:
set_result(xfail_status)
elif self.runtime.result.execution.status in (None, PYTEST_TO_QASE_STATUS['PASSED']):
set_result(PYTEST_TO_QASE_STATUS['SKIPPED'])
else:
xfail_status = handle_xfail_status()
if xfail_status:
set_result(xfail_status)
elif self.runtime.result.execution.status is None:
set_result(PYTEST_TO_QASE_STATUS['PASSED'])

if self.reporter.config.framework.pytest.capture_logs and call.when == "call":
attach_logs()

if hasattr(item, 'funcargs') and 'page' in item.funcargs and call.when == "call":
page = item.funcargs['page']
if page.video:
folder_name = self.__build_folder_name(item)
output_dir = self.config.framework.playwright.output_dir
base_path = os.path.join(os.getcwd(), output_dir, folder_name)

video_path = os.path.join(base_path, "video.webm")
self.add_attachments(video_path)

if self.config.framework.playwright.trace != Trace.off:
trace_path = os.path.join(base_path, "trace.zip")
self.add_attachments(trace_path)
else:
yield

def start_pytest_item(self, item):
self.runtime.result = Result(
Expand Down Expand Up @@ -389,7 +399,7 @@ def __sanitize_path_component(component):

@staticmethod
def __is_use_xfail_mark(report):
if report.keywords.get("xfail"):
if hasattr(report, 'wasxfail'):
return True
return False

Expand Down

0 comments on commit f89bbf4

Please sign in to comment.