diff --git a/pyproject.toml b/pyproject.toml index 95395b4..64f08e1 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,7 +28,7 @@ classifiers = [ "License :: OSI Approved :: MIT License", ] requires-python = ">=3.9" -dependencies = ["pytest>=2.8.1", "pyvirtualdisplay>=1.3"] +dependencies = ["pytest>=2.8.1", "pyvirtualdisplay>=1.3", "easyprocess"] [project.urls] Homepage = "https://github.com/The-Compiler/pytest-xvfb" diff --git a/pytest_xvfb.py b/pytest_xvfb.py index 7abb222..401d132 100644 --- a/pytest_xvfb.py +++ b/pytest_xvfb.py @@ -52,10 +52,12 @@ def __init__(self, config: pytest.Config) -> None: self.height = int(config.getini("xvfb_height")) self.colordepth = int(config.getini("xvfb_colordepth")) self.args = config.getini("xvfb_args") or [] - self.xauth = config.getini("xvfb_xauth") + self.wm = config.getini("xvfb_windowmanager") + self.xauth = True if self.wm else config.getini("xvfb_xauth") self.backend = config.getoption("--xvfb-backend") self.display: int | None = None self._virtual_display: pyvirtualdisplay.display.Display | None = None + self._wmprocess = None def start(self) -> None: self._virtual_display = pyvirtualdisplay.display.Display( @@ -66,12 +68,34 @@ def start(self) -> None: extra_args=self.args, ) self._virtual_display.start() + if self.wm: + from easyprocess import EasyProcess + import time + + self._wmprocess = EasyProcess(self.wm).start() + counter = 100 + while ( + "window id" + not in EasyProcess(["xprop", "-root", "_NET_SUPPORTING_WM_CHECK"]) + .call() + .stdout + ) and counter > 0: + time.sleep(0.1) + counter -= 1 self.display = self._virtual_display.display assert self._virtual_display.is_alive() + def __del__(self) -> None: + if self._wmprocess: + self._wmprocess.stop() + self._wmprocess = None + def stop(self) -> None: if self.display is not None: # starting worked assert self._virtual_display is not None # mypy + if self._wmprocess: + self._wmprocess.stop() + self._wmprocess = None self._virtual_display.stop() @@ -95,6 +119,7 @@ def pytest_addoption(parser: pytest.Parser) -> None: default=False, type="bool", ) + parser.addini("xvfb_windowmanager", "Run window manager", type="string", default="") def pytest_addhooks(pluginmanager: pytest.PytestPluginManager) -> None: diff --git a/tests/test_xvfb.py b/tests/test_xvfb.py index 783256a..3c2fc14 100644 --- a/tests/test_xvfb.py +++ b/tests/test_xvfb.py @@ -8,10 +8,20 @@ import pytest_xvfb +windowmanager = "herbstluftwm" + xauth_available = any( os.access(os.path.join(path, "xauth"), os.X_OK) for path in os.environ.get("PATH", "").split(os.pathsep) ) +wm_available = any( + os.access(os.path.join(path, windowmanager), os.X_OK) + for path in os.environ.get("PATH", "").split(os.pathsep) +) +wmctrl_available = any( + os.access(os.path.join(path, "wmctrl"), os.X_OK) + for path in os.environ.get("PATH", "").split(os.pathsep) +) @pytest.fixture(autouse=True, scope="session") @@ -367,3 +377,26 @@ def test_xauth(): # Make sure the authfile is deleted assert not os.path.exists(authfile) assert os.environ.get("XAUTHORITY") == original_auth + + +@pytest.mark.skipif(not wm_available, reason="no windowmanager") +@pytest.mark.skipif(not wmctrl_available, reason="no wmctrl") +def test_xvfb_with_wm(pytester: pytest.Pytester, backend_args: list[str]) -> None: + pytester.makeini( + f""" + [pytest] + xvfb_windowmanager = {windowmanager} + """ + ) + pytester.makepyfile( + f""" + import os + from easyprocess import EasyProcess + + def test_wm(): + assert "{windowmanager}" in EasyProcess(['wmctrl', '-m']).call().stdout + """ + ) + result = pytester.runpytest("-s", *backend_args) + + assert result.ret == 0