From 417a5b04628c769446665010f9232ec0bfbc7581 Mon Sep 17 00:00:00 2001 From: Max Schmitt Date: Tue, 15 Mar 2022 19:39:35 +0100 Subject: [PATCH] chore: roll Playwright to 1.20 (#1206) --- README.md | 4 +- playwright/_impl/_browser_type.py | 2 + playwright/_impl/_element_handle.py | 2 +- playwright/_impl/_locator.py | 2 +- playwright/_impl/_page.py | 2 +- playwright/async_api/_generated.py | 37 +++++++++++-------- playwright/sync_api/_generated.py | 37 +++++++++++-------- setup.py | 2 +- .../async/test_browsercontext_add_cookies.py | 24 ++++++++++-- tests/async/test_browsercontext_cookies.py | 18 ++++----- tests/async/test_defaultbrowsercontext.py | 29 +++++++++++---- tests/async/test_headful.py | 21 +++++++++-- tests/async/test_interception.py | 6 ++- tests/async/test_network.py | 3 +- tests/async/test_resource_timing.py | 3 +- tests/sync/test_resource_timing.py | 3 +- 16 files changed, 128 insertions(+), 67 deletions(-) diff --git a/README.md b/README.md index 198392a98..7bd679d0e 100644 --- a/README.md +++ b/README.md @@ -4,9 +4,9 @@ Playwright is a Python library to automate [Chromium](https://www.chromium.org/H | | Linux | macOS | Windows | | :--- | :---: | :---: | :---: | -| Chromium 101.0.4915.0 | ✅ | ✅ | ✅ | +| Chromium 101.0.4929.0 | ✅ | ✅ | ✅ | | WebKit 15.4 | ✅ | ✅ | ✅ | -| Firefox 96.0.1 | ✅ | ✅ | ✅ | +| Firefox 97.0.1 | ✅ | ✅ | ✅ | ## Documentation diff --git a/playwright/_impl/_browser_type.py b/playwright/_impl/_browser_type.py index f09f73ac8..3bb631145 100644 --- a/playwright/_impl/_browser_type.py +++ b/playwright/_impl/_browser_type.py @@ -182,6 +182,8 @@ async def connect( if timeout is None: timeout = 30000 + headers = {**(headers if headers else {}), "x-playwright-browser": self.name} + transport = WebSocketTransport( self._connection._loop, ws_endpoint, headers, slow_mo ) diff --git a/playwright/_impl/_element_handle.py b/playwright/_impl/_element_handle.py index ff46dabba..fea9a7237 100644 --- a/playwright/_impl/_element_handle.py +++ b/playwright/_impl/_element_handle.py @@ -270,7 +270,7 @@ async def screenshot( path: Union[str, Path] = None, quality: int = None, omitBackground: bool = None, - disableAnimations: bool = None, + animations: Literal["disabled"] = None, mask: List["Locator"] = None, ) -> bytes: params = locals_to_params(locals()) diff --git a/playwright/_impl/_locator.py b/playwright/_impl/_locator.py index e79f31fec..262aebbb6 100644 --- a/playwright/_impl/_locator.py +++ b/playwright/_impl/_locator.py @@ -373,7 +373,7 @@ async def screenshot( path: Union[str, pathlib.Path] = None, quality: int = None, omitBackground: bool = None, - disableAnimations: bool = None, + animations: Literal["disabled"] = None, mask: List["Locator"] = None, ) -> bytes: params = locals_to_params(locals()) diff --git a/playwright/_impl/_page.py b/playwright/_impl/_page.py index d6d6ddc2b..ed0a9d043 100644 --- a/playwright/_impl/_page.py +++ b/playwright/_impl/_page.py @@ -604,7 +604,7 @@ async def screenshot( omitBackground: bool = None, fullPage: bool = None, clip: FloatRect = None, - disableAnimations: bool = None, + animations: Literal["disabled"] = None, mask: List["Locator"] = None, ) -> bytes: params = locals_to_params(locals()) diff --git a/playwright/async_api/_generated.py b/playwright/async_api/_generated.py index ac55e62d1..b592d5971 100644 --- a/playwright/async_api/_generated.py +++ b/playwright/async_api/_generated.py @@ -2537,7 +2537,7 @@ async def screenshot( path: typing.Union[str, pathlib.Path] = None, quality: int = None, omit_background: bool = None, - disable_animations: bool = None, + animations: Literal["disabled"] = None, mask: typing.List["Locator"] = None ) -> bytes: """ElementHandle.screenshot @@ -2563,9 +2563,11 @@ async def screenshot( omit_background : Union[bool, NoneType] Hides default white background and allows capturing screenshots with transparency. Not applicable to `jpeg` images. Defaults to `false`. - disable_animations : Union[bool, NoneType] - When true, stops CSS animations, CSS transitions and Web Animations. Animations get different treatment depending on - their duration: + animations : Union["disabled", NoneType] + When set to `"disabled"`, stops CSS animations, CSS transitions and Web Animations. Animations get different treatment + depending on their duration: + - finite animations are fast-forwarded to completion, so they'll fire `transitionend` event. + - infinite animations are canceled to initial state, and then played over after the screenshot. mask : Union[List[Locator], NoneType] Specify locators that should be masked when the screenshot is taken. Masked elements will be overlayed with a pink box `#FF00FF` that completely covers its bounding box. @@ -2584,7 +2586,7 @@ async def screenshot( path=path, quality=quality, omitBackground=omit_background, - disableAnimations=disable_animations, + animations=animations, mask=mapping.to_impl(mask), ), ) @@ -8054,7 +8056,7 @@ async def screenshot( omit_background: bool = None, full_page: bool = None, clip: FloatRect = None, - disable_animations: bool = None, + animations: Literal["disabled"] = None, mask: typing.List["Locator"] = None ) -> bytes: """Page.screenshot @@ -8082,9 +8084,11 @@ async def screenshot( `false`. clip : Union[{x: float, y: float, width: float, height: float}, NoneType] An object which specifies clipping of the resulting image. Should have the following fields: - disable_animations : Union[bool, NoneType] - When true, stops CSS animations, CSS transitions and Web Animations. Animations get different treatment depending on - their duration: + animations : Union["disabled", NoneType] + When set to `"disabled"`, stops CSS animations, CSS transitions and Web Animations. Animations get different treatment + depending on their duration: + - finite animations are fast-forwarded to completion, so they'll fire `transitionend` event. + - infinite animations are canceled to initial state, and then played over after the screenshot. mask : Union[List[Locator], NoneType] Specify locators that should be masked when the screenshot is taken. Masked elements will be overlayed with a pink box `#FF00FF` that completely covers its bounding box. @@ -8105,7 +8109,7 @@ async def screenshot( omitBackground=omit_background, fullPage=full_page, clip=clip, - disableAnimations=disable_animations, + animations=animations, mask=mapping.to_impl(mask), ), ) @@ -10431,7 +10435,6 @@ async def grant_permissions( - `'midi'` - `'midi-sysex'` (system-exclusive midi) - `'notifications'` - - `'push'` - `'camera'` - `'microphone'` - `'background-sync'` @@ -13342,7 +13345,7 @@ async def screenshot( path: typing.Union[str, pathlib.Path] = None, quality: int = None, omit_background: bool = None, - disable_animations: bool = None, + animations: Literal["disabled"] = None, mask: typing.List["Locator"] = None ) -> bytes: """Locator.screenshot @@ -13368,9 +13371,11 @@ async def screenshot( omit_background : Union[bool, NoneType] Hides default white background and allows capturing screenshots with transparency. Not applicable to `jpeg` images. Defaults to `false`. - disable_animations : Union[bool, NoneType] - When true, stops CSS animations, CSS transitions and Web Animations. Animations get different treatment depending on - their duration: + animations : Union["disabled", NoneType] + When set to `"disabled"`, stops CSS animations, CSS transitions and Web Animations. Animations get different treatment + depending on their duration: + - finite animations are fast-forwarded to completion, so they'll fire `transitionend` event. + - infinite animations are canceled to initial state, and then played over after the screenshot. mask : Union[List[Locator], NoneType] Specify locators that should be masked when the screenshot is taken. Masked elements will be overlayed with a pink box `#FF00FF` that completely covers its bounding box. @@ -13389,7 +13394,7 @@ async def screenshot( path=path, quality=quality, omitBackground=omit_background, - disableAnimations=disable_animations, + animations=animations, mask=mapping.to_impl(mask), ), ) diff --git a/playwright/sync_api/_generated.py b/playwright/sync_api/_generated.py index 58d078b62..d134c246b 100644 --- a/playwright/sync_api/_generated.py +++ b/playwright/sync_api/_generated.py @@ -2486,7 +2486,7 @@ def screenshot( path: typing.Union[str, pathlib.Path] = None, quality: int = None, omit_background: bool = None, - disable_animations: bool = None, + animations: Literal["disabled"] = None, mask: typing.List["Locator"] = None ) -> bytes: """ElementHandle.screenshot @@ -2512,9 +2512,11 @@ def screenshot( omit_background : Union[bool, NoneType] Hides default white background and allows capturing screenshots with transparency. Not applicable to `jpeg` images. Defaults to `false`. - disable_animations : Union[bool, NoneType] - When true, stops CSS animations, CSS transitions and Web Animations. Animations get different treatment depending on - their duration: + animations : Union["disabled", NoneType] + When set to `"disabled"`, stops CSS animations, CSS transitions and Web Animations. Animations get different treatment + depending on their duration: + - finite animations are fast-forwarded to completion, so they'll fire `transitionend` event. + - infinite animations are canceled to initial state, and then played over after the screenshot. mask : Union[List[Locator], NoneType] Specify locators that should be masked when the screenshot is taken. Masked elements will be overlayed with a pink box `#FF00FF` that completely covers its bounding box. @@ -2533,7 +2535,7 @@ def screenshot( path=path, quality=quality, omitBackground=omit_background, - disableAnimations=disable_animations, + animations=animations, mask=mapping.to_impl(mask), ), ) @@ -7865,7 +7867,7 @@ def screenshot( omit_background: bool = None, full_page: bool = None, clip: FloatRect = None, - disable_animations: bool = None, + animations: Literal["disabled"] = None, mask: typing.List["Locator"] = None ) -> bytes: """Page.screenshot @@ -7893,9 +7895,11 @@ def screenshot( `false`. clip : Union[{x: float, y: float, width: float, height: float}, NoneType] An object which specifies clipping of the resulting image. Should have the following fields: - disable_animations : Union[bool, NoneType] - When true, stops CSS animations, CSS transitions and Web Animations. Animations get different treatment depending on - their duration: + animations : Union["disabled", NoneType] + When set to `"disabled"`, stops CSS animations, CSS transitions and Web Animations. Animations get different treatment + depending on their duration: + - finite animations are fast-forwarded to completion, so they'll fire `transitionend` event. + - infinite animations are canceled to initial state, and then played over after the screenshot. mask : Union[List[Locator], NoneType] Specify locators that should be masked when the screenshot is taken. Masked elements will be overlayed with a pink box `#FF00FF` that completely covers its bounding box. @@ -7916,7 +7920,7 @@ def screenshot( omitBackground=omit_background, fullPage=full_page, clip=clip, - disableAnimations=disable_animations, + animations=animations, mask=mapping.to_impl(mask), ), ) @@ -10187,7 +10191,6 @@ def grant_permissions( - `'midi'` - `'midi-sysex'` (system-exclusive midi) - `'notifications'` - - `'push'` - `'camera'` - `'microphone'` - `'background-sync'` @@ -13062,7 +13065,7 @@ def screenshot( path: typing.Union[str, pathlib.Path] = None, quality: int = None, omit_background: bool = None, - disable_animations: bool = None, + animations: Literal["disabled"] = None, mask: typing.List["Locator"] = None ) -> bytes: """Locator.screenshot @@ -13088,9 +13091,11 @@ def screenshot( omit_background : Union[bool, NoneType] Hides default white background and allows capturing screenshots with transparency. Not applicable to `jpeg` images. Defaults to `false`. - disable_animations : Union[bool, NoneType] - When true, stops CSS animations, CSS transitions and Web Animations. Animations get different treatment depending on - their duration: + animations : Union["disabled", NoneType] + When set to `"disabled"`, stops CSS animations, CSS transitions and Web Animations. Animations get different treatment + depending on their duration: + - finite animations are fast-forwarded to completion, so they'll fire `transitionend` event. + - infinite animations are canceled to initial state, and then played over after the screenshot. mask : Union[List[Locator], NoneType] Specify locators that should be masked when the screenshot is taken. Masked elements will be overlayed with a pink box `#FF00FF` that completely covers its bounding box. @@ -13109,7 +13114,7 @@ def screenshot( path=path, quality=quality, omitBackground=omit_background, - disableAnimations=disable_animations, + animations=animations, mask=mapping.to_impl(mask), ), ) diff --git a/setup.py b/setup.py index 4ab2cf23e..efd2a600d 100644 --- a/setup.py +++ b/setup.py @@ -30,7 +30,7 @@ InWheel = None from wheel.bdist_wheel import bdist_wheel as BDistWheelCommand -driver_version = "1.20.0-alpha-1646324243000" +driver_version = "1.20.0" def extractall(zip: zipfile.ZipFile, path: str) -> None: diff --git a/tests/async/test_browsercontext_add_cookies.py b/tests/async/test_browsercontext_add_cookies.py index 43775b96c..6ce2e6088 100644 --- a/tests/async/test_browsercontext_add_cookies.py +++ b/tests/async/test_browsercontext_add_cookies.py @@ -302,7 +302,7 @@ async def test_should_default_to_setting_secure_cookie_for_https_websites( async def test_should_be_able_to_set_unsecure_cookie_for_http_website( - context, page, server, is_firefox + context, page, server ): await page.goto(server.EMPTY_PAGE) HTTP_URL = "http://example.com" @@ -354,7 +354,9 @@ async def test_should_set_cookies_for_a_frame(context, page, server): assert await page.frames[1].evaluate("document.cookie") == "frame-cookie=value" -async def test_should_not_block_third_party_cookies(context, page, server): +async def test_should_not_block_third_party_cookies( + context, page, server, is_chromium, is_firefox +): await page.goto(server.EMPTY_PAGE) await page.evaluate( """src => { @@ -370,5 +372,21 @@ async def test_should_not_block_third_party_cookies(context, page, server): ) await page.frames[1].evaluate("document.cookie = 'username=John Doe'") await page.wait_for_timeout(2000) + allows_third_party = is_firefox cookies = await context.cookies(server.CROSS_PROCESS_PREFIX + "/grid.html") - assert cookies == [] + + if allows_third_party: + assert cookies == [ + { + "domain": "127.0.0.1", + "expires": -1, + "httpOnly": False, + "name": "username", + "path": "/", + "sameSite": "Lax" if is_chromium else "None", + "secure": False, + "value": "John Doe", + } + ] + else: + assert cookies == [] diff --git a/tests/async/test_browsercontext_cookies.py b/tests/async/test_browsercontext_cookies.py index e391caefe..e0ac33740 100644 --- a/tests/async/test_browsercontext_cookies.py +++ b/tests/async/test_browsercontext_cookies.py @@ -21,7 +21,7 @@ async def test_should_return_no_cookies_in_pristine_browser_context(context): assert await context.cookies() == [] -async def test_should_get_a_cookie(context, page, server, is_chromium, is_firefox): +async def test_should_get_a_cookie(context, page, server, is_chromium): await page.goto(server.EMPTY_PAGE) document_cookie = await page.evaluate( """() => { @@ -39,14 +39,12 @@ async def test_should_get_a_cookie(context, page, server, is_chromium, is_firefo "expires": -1, "httpOnly": False, "secure": False, - "sameSite": "Lax" if (is_chromium or is_firefox) else "None", + "sameSite": "Lax" if is_chromium else "None", } ] -async def test_should_get_a_non_session_cookie( - context, page, server, is_chromium, is_firefox -): +async def test_should_get_a_non_session_cookie(context, page, server, is_chromium): await page.goto(server.EMPTY_PAGE) # @see https://en.wikipedia.org/wiki/Year_2038_problem date = int(datetime.datetime(2038, 1, 1).timestamp() * 1000) @@ -68,7 +66,7 @@ async def test_should_get_a_non_session_cookie( "expires": date / 1000, "httpOnly": False, "secure": False, - "sameSite": "Lax" if (is_chromium or is_firefox) else "None", + "sameSite": "Lax" if is_chromium else "None", } ] @@ -126,9 +124,7 @@ async def test_should_properly_report_lax_sameSite_cookie( assert cookies[0]["sameSite"] == "Lax" -async def test_should_get_multiple_cookies( - context, page, server, is_chromium, is_firefox -): +async def test_should_get_multiple_cookies(context, page, server, is_chromium): await page.goto(server.EMPTY_PAGE) document_cookie = await page.evaluate( """() => { @@ -149,7 +145,7 @@ async def test_should_get_multiple_cookies( "expires": -1, "httpOnly": False, "secure": False, - "sameSite": "Lax" if (is_chromium or is_firefox) else "None", + "sameSite": "Lax" if is_chromium else "None", }, { "name": "username", @@ -159,7 +155,7 @@ async def test_should_get_multiple_cookies( "expires": -1, "httpOnly": False, "secure": False, - "sameSite": "Lax" if (is_chromium or is_firefox) else "None", + "sameSite": "Lax" if is_chromium else "None", }, ] diff --git a/tests/async/test_defaultbrowsercontext.py b/tests/async/test_defaultbrowsercontext.py index b494705ee..1e247ca51 100644 --- a/tests/async/test_defaultbrowsercontext.py +++ b/tests/async/test_defaultbrowsercontext.py @@ -37,9 +37,7 @@ async def _launch(**options): await context.close() -async def test_context_cookies_should_work( - server, launch_persistent, is_chromium, is_firefox -): +async def test_context_cookies_should_work(server, launch_persistent, is_chromium): (page, context) = await launch_persistent() await page.goto(server.EMPTY_PAGE) document_cookie = await page.evaluate( @@ -59,7 +57,7 @@ async def test_context_cookies_should_work( "expires": -1, "httpOnly": False, "secure": False, - "sameSite": "Lax" if (is_chromium or is_firefox) else "None", + "sameSite": "Lax" if is_chromium else "None", } ] @@ -101,7 +99,9 @@ async def test_context_clear_cookies_should_work(server, launch_persistent): assert await page.evaluate("document.cookie") == "" -async def test_should_not_block_third_party_cookies(server, launch_persistent): +async def test_should_not_block_third_party_cookies( + server, launch_persistent, is_chromium, is_firefox +): (page, context) = await launch_persistent() await page.goto(server.EMPTY_PAGE) await page.evaluate( @@ -124,9 +124,24 @@ async def test_should_not_block_third_party_cookies(server, launch_persistent): ) await page.wait_for_timeout(2000) - assert document_cookie == "" + allows_third_party = is_firefox + assert document_cookie == ("username=John Doe" if allows_third_party else "") cookies = await context.cookies(server.CROSS_PROCESS_PREFIX + "/grid.html") - assert cookies == [] + if allows_third_party: + assert cookies == [ + { + "domain": "127.0.0.1", + "expires": -1, + "httpOnly": False, + "name": "username", + "path": "/", + "sameSite": "None", + "secure": False, + "value": "John Doe", + } + ] + else: + assert cookies == [] async def test_should_support_viewport_option(launch_persistent, utils): diff --git a/tests/async/test_headful.py b/tests/async/test_headful.py index 742281057..8939bf0c2 100644 --- a/tests/async/test_headful.py +++ b/tests/async/test_headful.py @@ -76,7 +76,7 @@ async def test_should_close_browser_after_context_menu_was_triggered( async def test_should_not_block_third_party_cookies( - browser_type, launch_arguments, server + browser_type, launch_arguments, server, is_chromium, is_firefox ): browser = await browser_type.launch(**{**launch_arguments, "headless": False}) page = await browser.new_page() @@ -101,9 +101,24 @@ async def test_should_not_block_third_party_cookies( ) await page.wait_for_timeout(2000) - assert document_cookie == "" + allows_third_party = is_firefox + assert document_cookie == ("username=John Doe" if allows_third_party else "") cookies = await page.context.cookies(server.CROSS_PROCESS_PREFIX + "/grid.html") - assert cookies == [] + if allows_third_party: + assert cookies == [ + { + "domain": "127.0.0.1", + "expires": -1, + "httpOnly": False, + "name": "username", + "path": "/", + "sameSite": "Lax" if is_chromium else "None", + "secure": False, + "value": "John Doe", + } + ] + else: + assert cookies == [] await browser.close() diff --git a/tests/async/test_interception.py b/tests/async/test_interception.py index 7e67c5578..e3a7fed79 100644 --- a/tests/async/test_interception.py +++ b/tests/async/test_interception.py @@ -347,7 +347,8 @@ async def test_page_route_should_work_with_redirects_for_subresources(page, serv assert response.status == 200 assert "one-style.html" in response.url - assert len(intercepted) == 2 + # TODO: https://github.com/microsoft/playwright/issues/12789 + assert len(intercepted) >= 2 assert intercepted[0].resource_type == "document" assert "one-style.html" in intercepted[0].url @@ -478,7 +479,8 @@ async def test_page_route_should_work_with_encoded_server___2(page, server): f"""data:text/html,""" ) assert response is None - assert len(requests) == 1 + # TODO: https://github.com/microsoft/playwright/issues/12789 + assert len(requests) >= 1 assert (await requests[0].response()).status == 404 diff --git a/tests/async/test_network.py b/tests/async/test_network.py index 73081e04a..b6b2f22e9 100644 --- a/tests/async/test_network.py +++ b/tests/async/test_network.py @@ -588,7 +588,8 @@ def handle_request(request): failed_requests = [] page.on("requestfailed", lambda request: failed_requests.append(request)) await page.goto(server.PREFIX + "/one-style.html") - assert len(failed_requests) == 1 + # TODO: https://github.com/microsoft/playwright/issues/12789 + assert len(failed_requests) >= 1 assert "one-style.css" in failed_requests[0].url assert await failed_requests[0].response() is None assert failed_requests[0].resource_type == "stylesheet" diff --git a/tests/async/test_resource_timing.py b/tests/async/test_resource_timing.py index 8195374e7..904118aaa 100644 --- a/tests/async/test_resource_timing.py +++ b/tests/async/test_resource_timing.py @@ -41,7 +41,8 @@ async def test_should_work_for_subresource(page, server, is_win, is_mac, is_webk requests = [] page.on("requestfinished", lambda request: requests.append(request)) await page.goto(server.PREFIX + "/one-style.html") - assert len(requests) == 2 + # TODO: https://github.com/microsoft/playwright/issues/12789 + assert len(requests) >= 2 timing = requests[1].timing if is_webkit and is_win: # Curl does not reuse connections. diff --git a/tests/sync/test_resource_timing.py b/tests/sync/test_resource_timing.py index a26b61a63..f98dbdbd7 100644 --- a/tests/sync/test_resource_timing.py +++ b/tests/sync/test_resource_timing.py @@ -46,7 +46,8 @@ def test_should_work_for_subresource( requests = [] page.on("requestfinished", lambda request: requests.append(request)) page.goto(server.PREFIX + "/one-style.html") - assert len(requests) == 2 + # TODO: https://github.com/microsoft/playwright/issues/12789 + assert len(requests) >= 2 timing = requests[1].timing if is_webkit and is_win: # Curl does not reuse connections.