Skip to content

Commit

Permalink
feat: allow connecting via connect_options (#269)
Browse files Browse the repository at this point in the history
  • Loading branch information
mxschmitt authored Jan 30, 2025
1 parent a69386c commit 36ee721
Show file tree
Hide file tree
Showing 6 changed files with 146 additions and 4 deletions.
5 changes: 4 additions & 1 deletion .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,10 @@ jobs:
python-version: 3.9
channels: microsoft,conda-forge
- name: Prepare
run: conda install conda-build conda-verify
run: |
conda install conda-build conda-verify
# Until https://github.com/anaconda/conda-anaconda-telemetry/issues/87 has been fixed
conda remove --name base conda-anaconda-telemetry
- name: Build pytest-playwright
run: conda build .
- name: Build pytest-playwright-asyncio
Expand Down
5 changes: 4 additions & 1 deletion .github/workflows/python-publish.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,10 @@ jobs:
python-version: 3.9
channels: microsoft,conda-forge
- name: Prepare
run: conda install anaconda-client conda-build conda-verify
run: |
conda install anaconda-client conda-build conda-verify
# Until https://github.com/anaconda/conda-anaconda-telemetry/issues/87 has been fixed
conda remove --name base conda-anaconda-telemetry
- name: Build and Upload
env:
ANACONDA_API_TOKEN: ${{ secrets.ANACONDA_API_TOKEN }}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
# limitations under the License.

import hashlib
import json
import shutil
import os
import sys
Expand Down Expand Up @@ -247,14 +248,33 @@ def browser_type(playwright: Playwright, browser_name: str) -> BrowserType:
return getattr(playwright, browser_name)


@pytest.fixture(scope="session")
def connect_options() -> Optional[Dict]:
return None


@pytest.fixture(scope="session")
def launch_browser(
browser_type_launch_args: Dict,
browser_type: BrowserType,
connect_options: Optional[Dict],
) -> Callable[..., Awaitable[Browser]]:
async def launch(**kwargs: Dict) -> Browser:
launch_options = {**browser_type_launch_args, **kwargs}
browser = await browser_type.launch(**launch_options)
if connect_options:
browser = await browser_type.connect(
**(
{
**connect_options,
"headers": {
"x-playwright-launch-options": json.dumps(launch_options),
**(connect_options.get("headers") or {}),
},
}
)
)
else:
browser = await browser_type.launch(**launch_options)
return browser

return launch
Expand Down
22 changes: 21 additions & 1 deletion pytest-playwright/pytest_playwright/pytest_playwright.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
# limitations under the License.

import hashlib
import json
import shutil
import os
import sys
Expand Down Expand Up @@ -244,14 +245,33 @@ def browser_type(playwright: Playwright, browser_name: str) -> BrowserType:
return getattr(playwright, browser_name)


@pytest.fixture(scope="session")
def connect_options() -> Optional[Dict]:
return None


@pytest.fixture(scope="session")
def launch_browser(
browser_type_launch_args: Dict,
browser_type: BrowserType,
connect_options: Optional[Dict],
) -> Callable[..., Browser]:
def launch(**kwargs: Dict) -> Browser:
launch_options = {**browser_type_launch_args, **kwargs}
browser = browser_type.launch(**launch_options)
if connect_options:
browser = browser_type.connect(
**(
{
**connect_options,
"headers": {
"x-playwright-launch-options": json.dumps(launch_options),
**(connect_options.get("headers") or {}),
},
}
)
)
else:
browser = browser_type.launch(**launch_options)
return browser

return launch
Expand Down
50 changes: 50 additions & 0 deletions tests/test_asyncio.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@
# limitations under the License.

import os
import signal
import subprocess
import sys

import pytest
Expand Down Expand Up @@ -1019,3 +1021,51 @@ def test_with_page(page):
"test-results/test-output-path-via-pytest-runtest-makereport-hook-py-test-with-page-chromium"
).strpath,
]


def test_connect_options_should_work(testdir: pytest.Testdir) -> None:
server_process = None
try:
testdir.makeconftest(
"""
import pytest
@pytest.fixture(scope="session")
def connect_options():
return {
"ws_endpoint": "ws://localhost:1234",
}
"""
)
testdir.makepyfile(
"""
import pytest
@pytest.mark.asyncio(loop_scope="session")
async def test_connect_options(page):
assert await page.evaluate("1 + 1") == 2
"""
)
result = testdir.runpytest()
assert "connect ECONNREFUSED" in "".join(result.outlines)
server_process = subprocess.Popen(
["playwright", "run-server", "--port=1234"],
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
)
while True:
stdout = server_process.stdout
assert stdout
if "Listening on" in str(stdout.readline()):
break
result = testdir.runpytest()
result.assert_outcomes(passed=1)
finally:
assert server_process
# TODO: Playwright CLI on Windows via Python does not forward the signal
# hence we need to send it to the whole process group.
if sys.platform == "win32":
subprocess.run(["taskkill", "/F", "/T", "/PID", str(server_process.pid)])
else:
os.kill(server_process.pid, signal.SIGINT)
server_process.wait()
46 changes: 46 additions & 0 deletions tests/test_sync.py
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@

import os
from pathlib import Path
import signal
import subprocess
import sys

import pytest
Expand Down Expand Up @@ -982,3 +984,47 @@ def test_with_page(page):
"test-results/test-output-path-via-pytest-runtest-makereport-hook-py-test-with-page-chromium"
).strpath,
]


def test_connect_options_should_work(testdir: pytest.Testdir) -> None:
server_process = None
try:
testdir.makeconftest(
"""
import pytest
@pytest.fixture(scope="session")
def connect_options():
return {
"ws_endpoint": "ws://localhost:1234",
}
"""
)
testdir.makepyfile(
"""
def test_connect_options(page):
assert page.evaluate("1 + 1") == 2
"""
)
result = testdir.runpytest()
assert "connect ECONNREFUSED" in "".join(result.outlines)
server_process = subprocess.Popen(
["playwright", "run-server", "--port=1234"],
stdout=subprocess.PIPE,
)
while True:
stdout = server_process.stdout
assert stdout
if "Listening on" in str(stdout.readline()):
break
result = testdir.runpytest()
result.assert_outcomes(passed=1)
finally:
assert server_process
# TODO: Playwright CLI on Windows via Python does not forward the signal
# hence we need to send it to the whole process group.
if sys.platform == "win32":
subprocess.run(["taskkill", "/F", "/T", "/PID", str(server_process.pid)])
else:
os.kill(server_process.pid, signal.SIGINT)
server_process.wait()

0 comments on commit 36ee721

Please sign in to comment.