diff --git a/qase-pytest/changelog.md b/qase-pytest/changelog.md index 115e1536..a92314b6 100644 --- a/qase-pytest/changelog.md +++ b/qase-pytest/changelog.md @@ -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 @@ -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` diff --git a/qase-pytest/pyproject.toml b/qase-pytest/pyproject.toml index 123c41eb..30ec592e 100644 --- a/qase-pytest/pyproject.toml +++ b/qase-pytest/pyproject.toml @@ -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"] diff --git a/qase-pytest/src/qase/pytest/plugin.py b/qase-pytest/src/qase/pytest/plugin.py index e80e3244..ef5e62b2 100644 --- a/qase-pytest/src/qase/pytest/plugin.py +++ b/qase-pytest/src/qase/pytest/plugin.py @@ -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( @@ -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