diff --git a/playwright/_impl/_transport.py b/playwright/_impl/_transport.py index 3cc029e18..5b9557eab 100644 --- a/playwright/_impl/_transport.py +++ b/playwright/_impl/_transport.py @@ -22,6 +22,7 @@ from typing import Callable, Dict, Optional, Union from playwright._impl._driver import compute_driver_executable, get_driver_env +from playwright._impl._errors import Error from playwright._impl._helper import ParsedMessagePayload @@ -75,7 +76,11 @@ def send(self, message: Dict) -> None: pass def serialize_message(self, message: Dict) -> bytes: - msg = json.dumps(message) + try: + # NaN and Infinity are not valid JSON and would crash the driver. + msg = json.dumps(message, allow_nan=False) + except ValueError as e: + raise Error(str(e)) from None if "DEBUGP" in os.environ: # pragma: no cover print("\x1b[32mSEND>\x1b[0m", json.dumps(message, indent=2)) return msg.encode() diff --git a/tests/async/test_assertions.py b/tests/async/test_assertions.py index 05b35c630..9c31b12af 100644 --- a/tests/async/test_assertions.py +++ b/tests/async/test_assertions.py @@ -1218,3 +1218,13 @@ async def test_assertions_should_include_aria_snapshot_in_separate_section( actual_line = message.split("\n")[1] assert 'heading "Page Heading"' not in actual_line assert message.index('heading "Page Heading"') > message.index("Aria snapshot:") + + +@pytest.mark.parametrize("timeout", [float("inf"), float("-inf"), float("nan")]) +async def test_assertions_should_reject_non_finite_timeout( + page: Page, timeout: float +) -> None: + with pytest.raises(Error, match="Out of range float values are not JSON"): + await expect(page.locator("div")).to_be_visible(timeout=timeout) + # The driver connection must survive the rejected call. + assert await page.evaluate("1 + 1") == 2 diff --git a/tests/sync/test_assertions.py b/tests/sync/test_assertions.py index 5180c2461..90cf5a3be 100644 --- a/tests/sync/test_assertions.py +++ b/tests/sync/test_assertions.py @@ -1123,3 +1123,13 @@ def test_assertions_should_include_aria_snapshot_in_separate_section( actual_line = message.split("\n")[1] assert 'heading "Page Heading"' not in actual_line assert message.index('heading "Page Heading"') > message.index("Aria snapshot:") + + +@pytest.mark.parametrize("timeout", [float("inf"), float("-inf"), float("nan")]) +def test_assertions_should_reject_non_finite_timeout( + page: Page, timeout: float +) -> None: + with pytest.raises(Error, match="Out of range float values are not JSON"): + expect(page.locator("div")).to_be_visible(timeout=timeout) + # The driver connection must survive the rejected call. + assert page.evaluate("1 + 1") == 2