From 46e9cfe3aac95e73affdf9f77ce289ca926441b1 Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Wed, 6 Nov 2024 21:21:55 +0100 Subject: [PATCH] feat: expose output_path fixture --- pytest_playwright/pytest_playwright.py | 36 +++++++-------- tests/test_playwright.py | 61 ++++++++++++++++++++++++-- 2 files changed, 75 insertions(+), 22 deletions(-) diff --git a/pytest_playwright/pytest_playwright.py b/pytest_playwright/pytest_playwright.py index 0db5809..c0f40b7 100644 --- a/pytest_playwright/pytest_playwright.py +++ b/pytest_playwright/pytest_playwright.py @@ -180,15 +180,10 @@ def _is_debugger_attached() -> bool: return debugger.is_attached() -def _build_artifact_test_folder( - pytestconfig: Any, request: pytest.FixtureRequest, folder_or_file_name: str -) -> str: - output_dir = pytestconfig.getoption("--output") - return os.path.join( - output_dir, - _truncate_file_name(slugify(request.node.nodeid)), - _truncate_file_name(folder_or_file_name), - ) +@pytest.fixture +def output_path(pytestconfig: Any, request: pytest.FixtureRequest) -> str: + output_dir = Path(pytestconfig.getoption("--output")).absolute() + return os.path.join(output_dir, _truncate_file_name(slugify(request.node.nodeid))) def _truncate_file_name(file_name: str) -> str: @@ -222,12 +217,13 @@ def browser_context_args( @pytest.fixture() def _artifacts_recorder( request: pytest.FixtureRequest, + output_path: str, playwright: Playwright, pytestconfig: Any, _pw_artifacts_folder: tempfile.TemporaryDirectory, ) -> Generator["ArtifactsRecorder", None, None]: artifacts_recorder = ArtifactsRecorder( - pytestconfig, request, playwright, _pw_artifacts_folder + pytestconfig, request, output_path, playwright, _pw_artifacts_folder ) yield artifacts_recorder # If request.node is missing rep_call, then some error happened during execution @@ -462,12 +458,14 @@ def __init__( self, pytestconfig: Any, request: pytest.FixtureRequest, + output_path: str, playwright: Playwright, pw_artifacts_folder: tempfile.TemporaryDirectory, ) -> None: self._request = request self._pytestconfig = pytestconfig self._playwright = playwright + self._output_path = output_path self._pw_artifacts_folder = pw_artifacts_folder self._all_pages: List[Page] = [] @@ -476,6 +474,12 @@ def __init__( self._tracing_option = pytestconfig.getoption("--tracing") self._capture_trace = self._tracing_option in ["on", "retain-on-failure"] + def _build_artifact_test_folder(self, folder_or_file_name: str) -> str: + return os.path.join( + self._output_path, + _truncate_file_name(folder_or_file_name), + ) + def did_finish_test(self, failed: bool) -> None: screenshot_option = self._pytestconfig.getoption("--screenshot") capture_screenshot = screenshot_option == "on" or ( @@ -484,9 +488,7 @@ def did_finish_test(self, failed: bool) -> None: if capture_screenshot: for index, screenshot in enumerate(self._screenshots): human_readable_status = "failed" if failed else "finished" - screenshot_path = _build_artifact_test_folder( - self._pytestconfig, - self._request, + screenshot_path = self._build_artifact_test_folder( f"test-{human_readable_status}-{index+1}.png", ) os.makedirs(os.path.dirname(screenshot_path), exist_ok=True) @@ -502,9 +504,7 @@ def did_finish_test(self, failed: bool) -> None: trace_file_name = ( "trace.zip" if len(self._traces) == 1 else f"trace-{index+1}.zip" ) - trace_path = _build_artifact_test_folder( - self._pytestconfig, self._request, trace_file_name - ) + trace_path = self._build_artifact_test_folder(trace_file_name) os.makedirs(os.path.dirname(trace_path), exist_ok=True) shutil.move(trace, trace_path) else: @@ -527,9 +527,7 @@ def did_finish_test(self, failed: bool) -> None: else f"video-{index+1}.webm" ) video.save_as( - path=_build_artifact_test_folder( - self._pytestconfig, self._request, video_file_name - ) + path=self._build_artifact_test_folder(video_file_name) ) except Error: # Silent catch empty videos. diff --git a/tests/test_playwright.py b/tests/test_playwright.py index 0018589..f073a00 100644 --- a/tests/test_playwright.py +++ b/tests/test_playwright.py @@ -644,14 +644,18 @@ def test_passing(page): def test_artifacts_should_store_everything_if_on(testdir: pytest.Testdir) -> None: testdir.makepyfile( """ - def test_passing(page): + def test_passing(page, output_path): + print(f"\\n\\noutput_path = {output_path}\\n\\n") assert 2 == page.evaluate("1 + 1") - def test_failing(page): + def test_failing(page, output_path): + print(f"\\n\\noutput_path = {output_path}\\n\\n") raise Exception("Failed") """ ) - result = testdir.runpytest("--screenshot", "on", "--video", "on", "--tracing", "on") + result = testdir.runpytest( + "--screenshot", "on", "--video", "on", "--tracing", "on", "-s" + ) result.assert_outcomes(passed=1, failed=1) test_results_dir = os.path.join(testdir.tmpdir, "test-results") _assert_folder_structure( @@ -667,6 +671,18 @@ def test_failing(page): - video.webm """, ) + output_path = str(testdir.tmpdir) + output_paths = [ + line[14:] for line in result.outlines if f"output_path = {output_path}" in line + ] + assert output_paths == [ + testdir.tmpdir.join( + "test-results/test-artifacts-should-store-everything-if-on-py-test-passing-chromium" + ).strpath, + testdir.tmpdir.join( + "test-results/test-artifacts-should-store-everything-if-on-py-test-failing-chromium" + ).strpath, + ] def test_artifacts_retain_on_failure(testdir: pytest.Testdir) -> None: @@ -911,3 +927,42 @@ def test_artifact_collection(new_context): ) result = testdir.runpytest() result.assert_outcomes(passed=1) + + +def test_output_path_via_pytest_runtest_makereport_hook( + testdir: pytest.Testdir, +) -> None: + testdir.makeconftest( + """ +import pytest + +@pytest.hookimpl(hookwrapper=True) +def pytest_runtest_makereport(item, call): + outcome = yield + report = outcome.get_result() + + if report.when == "call": + output_path = item.funcargs.get("output_path") + print("\\n\\noutput_path = {}".format(output_path)) +""" + ) + + testdir.makepyfile( + """ +def test_without_output_path(): + pass + +def test_with_page(page): + pass +""" + ) + + result = testdir.runpytest("--screenshot", "on", "-s") + result.assert_outcomes(passed=2) + output_paths = [line[14:] for line in result.outlines if "output_path = " in line] + assert output_paths == [ + "None", + testdir.tmpdir.join( + "test-results/test-output-path-via-pytest-runtest-makereport-hook-py-test-with-page-chromium" + ).strpath, + ]