Skip to content

Commit 48e68b7

Browse files
fix: throw if both async/sync pytest-playwright plugins are loaded (#282)
1 parent 29e723f commit 48e68b7

File tree

6 files changed

+105
-7
lines changed

6 files changed

+105
-7
lines changed

.gitignore

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -144,3 +144,8 @@ dmypy.json
144144

145145
.DS_Store
146146
/test-results/
147+
148+
# Claude Code local configuration files
149+
.claude/
150+
CLAUDE.local.md
151+
DEVELOPER.local.md

pytest-playwright-asyncio/pytest_playwright_asyncio/pytest_playwright.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -282,7 +282,7 @@ async def launch(**kwargs: Dict) -> Browser:
282282

283283
@pytest_asyncio.fixture(scope="session")
284284
async def browser(
285-
launch_browser: Callable[[], Awaitable[Browser]]
285+
launch_browser: Callable[[], Awaitable[Browser]],
286286
) -> AsyncGenerator[Browser, None]:
287287
browser = await launch_browser()
288288
yield browser
@@ -413,7 +413,14 @@ def device(pytestconfig: Any) -> Optional[str]:
413413
return pytestconfig.getoption("--device")
414414

415415

416-
def pytest_addoption(parser: Any) -> None:
416+
def pytest_addoption(
417+
parser: pytest.Parser, pluginmanager: pytest.PytestPluginManager
418+
) -> None:
419+
# Check for incompatible sync plugin early
420+
if pluginmanager.has_plugin("pytest_playwright.pytest_playwright"):
421+
raise RuntimeError(
422+
"pytest-playwright and pytest-playwright-asyncio are not compatible. Please use only one of them."
423+
)
417424
group = parser.getgroup("playwright", "Playwright")
418425
group.addoption(
419426
"--browser",

pytest-playwright/pytest_playwright/pytest_playwright.py

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -408,7 +408,14 @@ def device(pytestconfig: Any) -> Optional[str]:
408408
return pytestconfig.getoption("--device")
409409

410410

411-
def pytest_addoption(parser: Any) -> None:
411+
def pytest_addoption(
412+
parser: pytest.Parser, pluginmanager: pytest.PytestPluginManager
413+
) -> None:
414+
# Check for incompatible async plugin early
415+
if pluginmanager.has_plugin("pytest_playwright_asyncio.pytest_playwright"):
416+
raise RuntimeError(
417+
"pytest-playwright and pytest-playwright-asyncio are not compatible. Please use only one of them."
418+
)
412419
group = parser.getgroup("playwright", "Playwright")
413420
group.addoption(
414421
"--browser",

tests/conftest.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,14 +15,19 @@
1515
import sys
1616
import os
1717
import socket
18-
from typing import Generator, Optional, Type
18+
from typing import Any, Generator, Optional, Type
1919
import pytest
2020
import threading
2121
import http.server
2222
import socketserver
2323

2424
pytest_plugins = ["pytester"]
2525

26+
27+
def pytest_configure(config: Any) -> None:
28+
config.addinivalue_line("markers", "no_add_ini: mark test to skip adding ini file")
29+
30+
2631
# The testdir fixture which we use to perform unit tests will set the home directory
2732
# To a temporary directory of the created test. This would result that the browsers will
2833
# be re-downloaded each time. By setting the pw browser path directory we can prevent that.

tests/test_asyncio.py

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,9 @@ def pytester(pytester: pytest.Pytester) -> pytest.Pytester:
3232

3333

3434
@pytest.fixture(autouse=True)
35-
def _add_async_marker(testdir: pytest.Testdir) -> None:
35+
def _add_ini_asyncio(request: pytest.FixtureRequest, testdir: pytest.Testdir) -> None:
36+
if "no_add_ini" in request.keywords:
37+
return
3638
testdir.makefile(
3739
".ini",
3840
pytest="""
@@ -44,6 +46,42 @@ def _add_async_marker(testdir: pytest.Testdir) -> None:
4446
)
4547

4648

49+
@pytest.mark.no_add_ini
50+
def test_sync_async_incompatibility(testdir: pytest.Testdir) -> None:
51+
# This test needs to load both playwright and playwright-asyncio plugins
52+
# to trigger the incompatibility check
53+
testdir.makefile(
54+
".ini",
55+
pytest="""
56+
[pytest]
57+
addopts = --maxfail=1
58+
asyncio_default_test_loop_scope = session
59+
asyncio_default_fixture_loop_scope = session
60+
""",
61+
)
62+
testdir.makepyfile(
63+
"""
64+
import pytest
65+
@pytest.mark.asyncio
66+
async def test_foo():
67+
pass
68+
"""
69+
)
70+
# Explicitly load both plugins to trigger the incompatibility
71+
result = testdir.runpytest(
72+
"-p",
73+
"pytest_playwright.pytest_playwright",
74+
"-p",
75+
"pytest_playwright_asyncio.pytest_playwright",
76+
)
77+
assert result.ret != 0
78+
output = "\n".join(result.outlines + result.errlines)
79+
assert (
80+
"pytest-playwright and pytest-playwright-asyncio are not compatible. Please use only one of them."
81+
in output
82+
)
83+
84+
4785
def test_default(testdir: pytest.Testdir) -> None:
4886
testdir.makepyfile(
4987
"""
@@ -237,7 +275,7 @@ async def test_is_firefox(page, browser_name, is_chromium, is_firefox, is_webkit
237275
assert is_chromium is False
238276
assert is_firefox
239277
assert is_webkit is False
240-
"""
278+
"""
241279
)
242280
result = testdir.runpytest("--browser", "firefox")
243281
result.assert_outcomes(passed=1)

tests/test_sync.py

Lines changed: 37 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,9 @@ def pytester(pytester: pytest.Pytester) -> pytest.Pytester:
3333

3434

3535
@pytest.fixture(autouse=True)
36-
def _add_ini(testdir: pytest.Testdir) -> None:
36+
def _add_ini(request: pytest.FixtureRequest, testdir: pytest.Testdir) -> None:
37+
if "no_add_ini" in request.keywords:
38+
return
3739
testdir.makefile(
3840
".ini",
3941
pytest="""
@@ -43,6 +45,40 @@ def _add_ini(testdir: pytest.Testdir) -> None:
4345
)
4446

4547

48+
@pytest.mark.no_add_ini
49+
def test_sync_async_incompatibility(testdir: pytest.Testdir) -> None:
50+
# This test needs to load both playwright and playwright-asyncio plugins
51+
# to trigger the incompatibility check
52+
testdir.makefile(
53+
".ini",
54+
pytest="""
55+
[pytest]
56+
addopts = --maxfail=1
57+
""",
58+
)
59+
testdir.makepyfile(
60+
"""
61+
import pytest
62+
63+
def test_foo():
64+
pass
65+
"""
66+
)
67+
# Explicitly load both plugins to trigger the incompatibility
68+
result = testdir.runpytest(
69+
"-p",
70+
"pytest_playwright.pytest_playwright",
71+
"-p",
72+
"pytest_playwright_asyncio.pytest_playwright",
73+
)
74+
assert result.ret != 0
75+
output = "\n".join(result.outlines + result.errlines)
76+
assert (
77+
"pytest-playwright and pytest-playwright-asyncio are not compatible. Please use only one of them."
78+
in output
79+
)
80+
81+
4682
def test_default(testdir: pytest.Testdir) -> None:
4783
testdir.makepyfile(
4884
"""

0 commit comments

Comments
 (0)