Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(roll): roll Playwright to v1.44.0 #2433

Merged
merged 4 commits into from
May 8, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,9 @@ Playwright is a Python library to automate [Chromium](https://www.chromium.org/H

| | Linux | macOS | Windows |
| :--- | :---: | :---: | :---: |
| Chromium <!-- GEN:chromium-version -->124.0.6367.29<!-- GEN:stop --> | ✅ | ✅ | ✅ |
| Chromium <!-- GEN:chromium-version -->125.0.6422.26<!-- GEN:stop --> | ✅ | ✅ | ✅ |
| WebKit <!-- GEN:webkit-version -->17.4<!-- GEN:stop --> | ✅ | ✅ | ✅ |
| Firefox <!-- GEN:firefox-version -->124.0<!-- GEN:stop --> | ✅ | ✅ | ✅ |
| Firefox <!-- GEN:firefox-version -->125.0.1<!-- GEN:stop --> | ✅ | ✅ | ✅ |

## Documentation

Expand Down
7 changes: 7 additions & 0 deletions ROLLING.md
Original file line number Diff line number Diff line change
Expand Up @@ -14,3 +14,10 @@
* generate API: `./scripts/update_api.sh`
* commit changes & send PR
* wait for bots to pass & merge the PR


## Fix typing issues with Playwright ToT

1. `cd playwright`
1. `API_JSON_MODE=1 node utils/doclint/generateApiJson.js > ../playwright-python/playwright/driver/package/api.json`
1. `./scripts/update_api.sh`
86 changes: 80 additions & 6 deletions playwright/_impl/_assertions.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,11 @@
from typing import Any, List, Optional, Pattern, Sequence, Union
from urllib.parse import urljoin

from playwright._impl._api_structures import ExpectedTextValue, FrameExpectOptions
from playwright._impl._api_structures import (
AriaRole,
ExpectedTextValue,
FrameExpectOptions,
)
from playwright._impl._connection import format_call_log
from playwright._impl._errors import Error
from playwright._impl._fetch import APIResponse
Expand Down Expand Up @@ -92,10 +96,10 @@ def _not(self) -> "PageAssertions":
async def to_have_title(
self, titleOrRegExp: Union[Pattern[str], str], timeout: float = None
) -> None:
__tracebackhide__ = True
expected_values = to_expected_text_values(
[titleOrRegExp], normalize_white_space=True
)
__tracebackhide__ = True
await self._expect_impl(
"to.have.title",
FrameExpectOptions(expectedText=expected_values, timeout=timeout),
Expand All @@ -110,13 +114,16 @@ async def not_to_have_title(
await self._not.to_have_title(titleOrRegExp, timeout)

async def to_have_url(
self, urlOrRegExp: Union[str, Pattern[str]], timeout: float = None
self,
urlOrRegExp: Union[str, Pattern[str]],
timeout: float = None,
ignoreCase: bool = None,
) -> None:
__tracebackhide__ = True
base_url = self._actual_page.context._options.get("baseURL")
if isinstance(urlOrRegExp, str) and base_url:
urlOrRegExp = urljoin(base_url, urlOrRegExp)
expected_text = to_expected_text_values([urlOrRegExp])
expected_text = to_expected_text_values([urlOrRegExp], ignoreCase=ignoreCase)
await self._expect_impl(
"to.have.url",
FrameExpectOptions(expectedText=expected_text, timeout=timeout),
Expand All @@ -125,10 +132,13 @@ async def to_have_url(
)

async def not_to_have_url(
self, urlOrRegExp: Union[Pattern[str], str], timeout: float = None
self,
urlOrRegExp: Union[Pattern[str], str],
timeout: float = None,
ignoreCase: bool = None,
) -> None:
__tracebackhide__ = True
await self._not.to_have_url(urlOrRegExp, timeout)
await self._not.to_have_url(urlOrRegExp, timeout, ignoreCase)


class LocatorAssertions(AssertionsBase):
Expand Down Expand Up @@ -704,6 +714,70 @@ async def not_to_be_in_viewport(
__tracebackhide__ = True
await self._not.to_be_in_viewport(ratio=ratio, timeout=timeout)

async def to_have_accessible_description(
self,
description: Union[str, Pattern[str]],
ignoreCase: bool = None,
timeout: float = None,
) -> None:
__tracebackhide__ = True
expected_values = to_expected_text_values([description], ignoreCase=ignoreCase)
await self._expect_impl(
"to.have.accessible.description",
FrameExpectOptions(expectedText=expected_values, timeout=timeout),
None,
"Locator expected to have accessible description",
)

async def not_to_have_accessible_description(
self,
name: Union[str, Pattern[str]],
ignoreCase: bool = None,
timeout: float = None,
) -> None:
__tracebackhide__ = True
await self._not.to_have_accessible_description(name, ignoreCase, timeout)

async def to_have_accessible_name(
self,
name: Union[str, Pattern[str]],
ignoreCase: bool = None,
timeout: float = None,
) -> None:
__tracebackhide__ = True
expected_values = to_expected_text_values([name], ignoreCase=ignoreCase)
await self._expect_impl(
"to.have.accessible.name",
FrameExpectOptions(expectedText=expected_values, timeout=timeout),
None,
"Locator expected to have accessible name",
)

async def not_to_have_accessible_name(
self,
name: Union[str, Pattern[str]],
ignoreCase: bool = None,
timeout: float = None,
) -> None:
__tracebackhide__ = True
await self._not.to_have_accessible_name(name, ignoreCase, timeout)

async def to_have_role(self, role: AriaRole, timeout: float = None) -> None:
__tracebackhide__ = True
if isinstance(role, Pattern):
raise Error('"role" argument in to_have_role must be a string')
expected_values = to_expected_text_values([role])
await self._expect_impl(
"to.have.role",
FrameExpectOptions(expectedText=expected_values, timeout=timeout),
None,
"Locator expected to have accessible role",
)

async def not_to_have_role(self, role: AriaRole, timeout: float = None) -> None:
__tracebackhide__ = True
await self._not.to_have_role(role, timeout)


class APIResponseAssertions:
def __init__(
Expand Down
1 change: 1 addition & 0 deletions playwright/_impl/_browser_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -510,6 +510,7 @@ def _on_close(self) -> None:
self._browser._contexts.remove(self)

self._dispose_har_routers()
self._tracing._reset_stack_counter()
self.emit(BrowserContext.Events.Close, self)

async def close(self, reason: str = None) -> None:
Expand Down
24 changes: 14 additions & 10 deletions playwright/_impl/_browser_type.py
Original file line number Diff line number Diff line change
Expand Up @@ -218,6 +218,20 @@ async def connect(
local_utils=self._connection.local_utils,
)
connection.mark_as_remote()

browser = None

def handle_transport_close(reason: Optional[str]) -> None:
if browser:
for context in browser.contexts:
for page in context.pages:
page._on_close()
context._on_close()
browser._on_close()
connection.cleanup(reason)

transport.once("close", handle_transport_close)

connection._is_sync = self._connection._is_sync
connection._loop.create_task(connection.run())
playwright_future = connection.playwright_future
Expand All @@ -240,16 +254,6 @@ async def connect(
self._did_launch_browser(browser)
browser._should_close_connection_on_close = True

def handle_transport_close() -> None:
for context in browser.contexts:
for page in context.pages:
page._on_close()
context._on_close()
browser._on_close()
connection.cleanup()

transport.once("close", handle_transport_close)

return browser

def _did_create_context(
Expand Down
8 changes: 3 additions & 5 deletions playwright/_impl/_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -284,10 +284,8 @@ async def stop_async(self) -> None:
await self._transport.wait_until_stopped()
self.cleanup()

def cleanup(self, cause: Exception = None) -> None:
self._closed_error = (
TargetClosedError(str(cause)) if cause else TargetClosedError()
)
def cleanup(self, cause: str = None) -> None:
self._closed_error = TargetClosedError(cause) if cause else TargetClosedError()
if self._init_task and not self._init_task.done():
self._init_task.cancel()
for ws_connection in self._child_ws_connections:
Expand All @@ -305,7 +303,7 @@ def call_on_object_with_known_name(
) -> None:
self._waiting_for_object[guid] = callback

def set_in_tracing(self, is_tracing: bool) -> None:
def set_is_tracing(self, is_tracing: bool) -> None:
if is_tracing:
self._tracing_count += 1
else:
Expand Down
1 change: 1 addition & 0 deletions playwright/_impl/_fetch.py
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ def __init__(

async def dispose(self) -> None:
await self._channel.send("dispose")
self._tracing._reset_stack_counter()

async def delete(
self,
Expand Down
2 changes: 1 addition & 1 deletion playwright/_impl/_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@
ForcedColors = Literal["active", "none", "null"]
ReducedMotion = Literal["no-preference", "null", "reduce"]
DocumentLoadState = Literal["commit", "domcontentloaded", "load", "networkidle"]
KeyboardModifier = Literal["Alt", "Control", "Meta", "Shift"]
KeyboardModifier = Literal["Alt", "Control", "ControlOrMeta", "Meta", "Shift"]
MouseButton = Literal["left", "middle", "right"]
ServiceWorkersPolicy = Literal["allow", "block"]
HarMode = Literal["full", "minimal"]
Expand Down
11 changes: 7 additions & 4 deletions playwright/_impl/_json_pipe.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,11 +13,12 @@
# limitations under the License.

import asyncio
from typing import Dict, cast
from typing import Dict, Optional, cast

from pyee.asyncio import AsyncIOEventEmitter

from playwright._impl._connection import Channel
from playwright._impl._errors import TargetClosedError
from playwright._impl._helper import Error, ParsedMessagePayload
from playwright._impl._transport import Transport

Expand Down Expand Up @@ -53,8 +54,10 @@ def handle_message(message: Dict) -> None:
return
self.on_message(cast(ParsedMessagePayload, message))

def handle_closed() -> None:
self.emit("close")
def handle_closed(reason: Optional[str]) -> None:
self.emit("close", reason)
if reason:
self.on_error_future.set_exception(TargetClosedError(reason))
self._stopped_future.set_result(None)

self._pipe_channel.on(
Expand All @@ -63,7 +66,7 @@ def handle_closed() -> None:
)
self._pipe_channel.on(
"closed",
lambda _: handle_closed(),
lambda params: handle_closed(params.get("reason")),
)

async def run(self) -> None:
Expand Down
3 changes: 3 additions & 0 deletions playwright/_impl/_locator.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,9 @@ async def _with_element(
finally:
await handle.dispose()

def _equals(self, locator: "Locator") -> bool:
return self._frame == locator._frame and self._selector == locator._selector

@property
def page(self) -> "Page":
return self._frame.page
Expand Down
Loading
Loading