From 13e4aa02c3cdf6100a641521488fd798d4f63792 Mon Sep 17 00:00:00 2001 From: Dmitry Gozman Date: Fri, 7 Aug 2020 18:11:43 -0700 Subject: [PATCH] feat: roll driver to 1.3.0-next.1596843106133, handle paths on the client side --- README.md | 4 +- api.json | 80 +++++++++---------- driver/package.json | 2 +- playwright/async_api.py | 32 ++++---- playwright/drivers/browsers.json | 2 +- playwright/page.py | 14 +++- playwright/sync_api.py | 32 ++++---- tests/async/test_browser.py | 2 +- .../async/test_browsercontext_add_cookies.py | 6 +- tests/async/test_browsercontext_cookies.py | 14 ++-- tests/async/test_defaultbrowsercontext.py | 8 +- tests/async/test_headful.py | 2 +- tests/async/test_navigation.py | 2 + tests/async/test_pdf.py | 6 ++ tests/sync/test_pdf.py | 6 ++ 15 files changed, 116 insertions(+), 96 deletions(-) diff --git a/README.md b/README.md index c209ca198..e2d317ae2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # 🎭 [Playwright](https://github.com/microsoft/playwright) for Python -[![PyPI version](https://badge.fury.io/py/playwright.svg)](https://pypi.python.org/pypi/playwright/) [![Join Slack](https://img.shields.io/badge/join-slack-infomational)](https://join.slack.com/t/playwright/shared_invite/enQtOTEyMTUxMzgxMjIwLThjMDUxZmIyNTRiMTJjNjIyMzdmZDA3MTQxZWUwZTFjZjQwNGYxZGM5MzRmNzZlMWI5ZWUyOTkzMjE5Njg1NDg) [![Chromium version](https://img.shields.io/badge/chromium-86.0.4217.0-blue.svg?logo=google-chrome)](https://www.chromium.org/Home) [![Firefox version](https://img.shields.io/badge/firefox-78.0b5-blue.svg?logo=mozilla-firefox)](https://www.mozilla.org/en-US/firefox/new/) [![WebKit version](https://img.shields.io/badge/webkit-14.0-blue.svg?logo=safari)](https://webkit.org/) +[![PyPI version](https://badge.fury.io/py/playwright.svg)](https://pypi.python.org/pypi/playwright/) [![Join Slack](https://img.shields.io/badge/join-slack-infomational)](https://join.slack.com/t/playwright/shared_invite/enQtOTEyMTUxMzgxMjIwLThjMDUxZmIyNTRiMTJjNjIyMzdmZDA3MTQxZWUwZTFjZjQwNGYxZGM5MzRmNzZlMWI5ZWUyOTkzMjE5Njg1NDg) [![Chromium version](https://img.shields.io/badge/chromium-86.0.4217.0-blue.svg?logo=google-chrome)](https://www.chromium.org/Home) [![Firefox version](https://img.shields.io/badge/firefox-79.0a1-blue.svg?logo=mozilla-firefox)](https://www.mozilla.org/en-US/firefox/new/) [![WebKit version](https://img.shields.io/badge/webkit-14.0-blue.svg?logo=safari)](https://webkit.org/) [![Coverage Status](https://coveralls.io/repos/github/microsoft/playwright-python/badge.svg?branch=master)](https://coveralls.io/github/microsoft/playwright-python?branch=master) ##### [Docs](#documentation) | [API reference](https://github.com/microsoft/playwright/blob/master/docs/api.md) @@ -11,7 +11,7 @@ Playwright is a Python library to automate [Chromium](https://www.chromium.org/H | :--- | :---: | :---: | :---: | | Chromium 86.0.4217.0 | ✅ | ✅ | ✅ | | WebKit 14.0 | ✅ | ✅ | ✅ | -| Firefox 78.0b5 | ✅ | ✅ | ✅ | +| Firefox 79.0a1 | ✅ | ✅ | ✅ | Headless execution is supported for all the browsers on all platforms. diff --git a/api.json b/api.json index 807be6d17..b0bf75cd2 100644 --- a/api.json +++ b/api.json @@ -1954,7 +1954,7 @@ "kind": "property", "name": "arg", "type": { - "name": "Serializable|JSHandle", + "name": "EvaluationArgument", "properties": {} }, "comment": "Optional argument to pass to `pageFunction`", @@ -2004,7 +2004,7 @@ "kind": "property", "name": "arg", "type": { - "name": "Serializable|JSHandle", + "name": "EvaluationArgument", "properties": {} }, "comment": "Optional argument to pass to `pageFunction`", @@ -2248,7 +2248,7 @@ "name": "Promise", "properties": {} }, - "comment": "This method fetches an element with `selector`, if element is not already checked, it scrolls it into view if needed, and then uses page.click to click in the center of the element.\nIf there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried.\nShortcut for page.mainFrame().check(selector[, options]).", + "comment": "This method waits for an element matching `selector`, waits for actionability checks. Then, if the element is not already checked, this method scrolls the element into view and uses elementHandle.click to click in the center of the element.\nIf there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried.\nShortcut for page.mainFrame().check(selector[, options]).", "returnComment": "Promise which resolves when the element matching `selector` is successfully checked. The Promise will be rejected if there is no element matching `selector`.", "required": true, "templates": [], @@ -2323,7 +2323,7 @@ "name": "Promise", "properties": {} }, - "comment": "This method fetches an element with `selector`, scrolls it into view if needed, and then uses page.mouse to click in the center of the element.\nIf there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried.\nShortcut for page.mainFrame().click(selector[, options]).", + "comment": "This method waits for an element matching `selector`, waits for actionability checks, then scrolls the element into view if needed and uses page.mouse to click in the center of the element.\nIf there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried.\nShortcut for page.mainFrame().click(selector[, options]).", "returnComment": "Promise which resolves when the element matching `selector` is successfully clicked. The Promise will be rejected if there is no element matching `selector`.", "required": true, "templates": [], @@ -2522,7 +2522,7 @@ "name": "Promise", "properties": {} }, - "comment": "This method fetches an element with `selector`, scrolls it into view if needed, and then uses page.mouse to double click in the center of the element.\nIf there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried.\nBear in mind that if the first click of the `dblclick()` triggers a navigation event, there will be an exception.\n\n**NOTE** `page.dblclick()` dispatches two `click` events and a single `dblclick` event.\n\nShortcut for page.mainFrame().dblclick(selector[, options]).", + "comment": "This method waits for an element matching `selector`, waits for actionability checks, then scrolls the element into view if needed and uses page.mouse to double click in the center of the element.\nIf there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried.\nBear in mind that if the first click of the `dblclick()` triggers a navigation event, there will be an exception.\n\n**NOTE** `page.dblclick()` dispatches two `click` events and a single `dblclick` event.\n\nShortcut for page.mainFrame().dblclick(selector[, options]).", "returnComment": "Promise which resolves when the element matching `selector` is successfully double clicked. The Promise will be rejected if there is no element matching `selector`.", "required": true, "templates": [], @@ -2817,7 +2817,7 @@ "kind": "property", "name": "arg", "type": { - "name": "Serializable|JSHandle", + "name": "EvaluationArgument", "properties": {} }, "comment": "Optional argument to pass to `pageFunction`", @@ -2855,7 +2855,7 @@ "kind": "property", "name": "arg", "type": { - "name": "Serializable|JSHandle", + "name": "EvaluationArgument", "properties": {} }, "comment": "Optional argument to pass to `pageFunction`", @@ -3378,7 +3378,7 @@ "name": "Promise", "properties": {} }, - "comment": "This method fetches an element with `selector`, scrolls it into view if needed, and then uses page.mouse to hover over the center of the element.\nIf there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried.\nShortcut for page.mainFrame().hover(selector[, options]).", + "comment": "This method waits for an element matching `selector`, waits for actionability checks, then scrolls the element into view if needed and uses page.mouse to hover over the center of the element.\nIf there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried.\nShortcut for page.mainFrame().hover(selector[, options]).", "returnComment": "Promise which resolves when the element matching `selector` is successfully hovered. Promise gets rejected if there's no element matching `selector`.", "required": true, "templates": [], @@ -4786,7 +4786,7 @@ "name": "Promise", "properties": {} }, - "comment": "This method fetches an element with `selector`, if element is not already unchecked, it scrolls it into view if needed, and then uses page.click to click in the center of the element.\nIf there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried.\nShortcut for page.mainFrame().uncheck(selector[, options]).", + "comment": "This method waits for an element matching `selector`, waits for actionability checks. Then, if the element is not already unchecked, this method scrolls the element into view and uses elementHandle.click to click in the center of the element.\nIf there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried.\nShortcut for page.mainFrame().uncheck(selector[, options]).", "returnComment": "Promise which resolves when the element matching `selector` is successfully unchecked. The Promise will be rejected if there is no element matching `selector`.", "required": true, "templates": [], @@ -5013,7 +5013,7 @@ "name": "Promise", "properties": {} }, - "comment": "The `waitForFunction` can be used to observe viewport size change:\n```js\nconst { webkit } = require('playwright'); // Or 'chromium' or 'firefox'.\n\n(async () => {\n const browser = await webkit.launch();\n const page = await browser.newPage();\n const watchDog = page.waitForFunction('window.innerWidth < 100');\n await page.setViewportSize({width: 50, height: 50});\n await watchDog;\n await browser.close();\n})();\n```\nTo pass an argument from Node.js to the predicate of `page.waitForFunction` function:\n```js\nconst selector = '.foo';\nawait page.waitForFunction(selector => !!document.querySelector(selector), selector);\n```\nShortcut for [page.mainFrame().waitForFunction(pageFunction, arg, options]])](#framewaitforfunctionpagefunction-arg-options).", + "comment": "The `waitForFunction` can be used to observe viewport size change:\n```js\nconst { webkit } = require('playwright'); // Or 'chromium' or 'firefox'.\n\n(async () => {\n const browser = await webkit.launch();\n const page = await browser.newPage();\n const watchDog = page.waitForFunction('window.innerWidth < 100');\n await page.setViewportSize({width: 50, height: 50});\n await watchDog;\n await browser.close();\n})();\n```\nTo pass an argument from Node.js to the predicate of `page.waitForFunction` function:\n```js\nconst selector = '.foo';\nawait page.waitForFunction(selector => !!document.querySelector(selector), selector);\n```\nShortcut for page.mainFrame().waitForFunction(pageFunction[, arg, options]).", "returnComment": "Promise which resolves when the `pageFunction` returns a truthy value. It resolves to a JSHandle of the truthy value.", "required": true, "templates": [], @@ -5034,7 +5034,7 @@ "kind": "property", "name": "arg", "type": { - "name": "Serializable|JSHandle", + "name": "EvaluationArgument", "properties": {} }, "comment": "Optional argument to pass to `pageFunction`", @@ -5496,7 +5496,7 @@ "kind": "property", "name": "arg", "type": { - "name": "Serializable|JSHandle", + "name": "EvaluationArgument", "properties": {} }, "comment": "Optional argument to pass to `pageFunction`", @@ -5546,7 +5546,7 @@ "kind": "property", "name": "arg", "type": { - "name": "Serializable|JSHandle", + "name": "EvaluationArgument", "properties": {} }, "comment": "Optional argument to pass to `pageFunction`", @@ -5701,7 +5701,7 @@ "name": "Promise", "properties": {} }, - "comment": "This method fetches an element with `selector`, if element is not already checked, it scrolls it into view if needed, and then uses frame.click to click in the center of the element.\nIf there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried.", + "comment": "This method waits for an element matching `selector`, waits for actionability checks. Then, if the element is not already checked, this method scrolls the element into view and uses elementHandle.click to click in the center of the element.\nIf there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried.", "returnComment": "Promise which resolves when the element matching `selector` is successfully checked. The Promise will be rejected if there is no element matching `selector`.", "required": true, "templates": [], @@ -5789,7 +5789,7 @@ "name": "Promise", "properties": {} }, - "comment": "This method fetches an element with `selector`, scrolls it into view if needed, and then uses page.mouse to click in the center of the element.\nIf there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried.", + "comment": "This method waits for an element matching `selector`, waits for actionability checks, then scrolls the element into view if needed and uses page.mouse to click in the center of the element.\nIf there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried.", "returnComment": "Promise which resolves when the element matching `selector` is successfully clicked. The Promise will be rejected if there is no element matching `selector`.", "required": true, "templates": [], @@ -5962,7 +5962,7 @@ "name": "Promise", "properties": {} }, - "comment": "This method fetches an element with `selector`, scrolls it into view if needed, and then uses page.mouse to double click in the center of the element.\nIf there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried.\nBear in mind that if the first click of the `dblclick()` triggers a navigation event, there will be an exception.\n\n**NOTE** `frame.dblclick()` dispatches two `click` events and a single `dblclick` event.", + "comment": "This method waits for an element matching `selector`, waits for actionability checks, then scrolls the element into view if needed and uses page.mouse to double click in the center of the element.\nIf there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried.\nBear in mind that if the first click of the `dblclick()` triggers a navigation event, there will be an exception.\n\n**NOTE** `frame.dblclick()` dispatches two `click` events and a single `dblclick` event.", "returnComment": "Promise which resolves when the element matching `selector` is successfully double clicked. The Promise will be rejected if there is no element matching `selector`.", "required": true, "templates": [], @@ -6206,7 +6206,7 @@ "kind": "property", "name": "arg", "type": { - "name": "Serializable|JSHandle", + "name": "EvaluationArgument", "properties": {} }, "comment": "Optional argument to pass to `pageFunction`", @@ -6244,7 +6244,7 @@ "kind": "property", "name": "arg", "type": { - "name": "Serializable|JSHandle", + "name": "EvaluationArgument", "properties": {} }, "comment": "Optional argument to pass to `pageFunction`", @@ -6538,7 +6538,7 @@ "name": "Promise", "properties": {} }, - "comment": "This method fetches an element with `selector`, scrolls it into view if needed, and then uses page.mouse to hover over the center of the element.\nIf there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried.", + "comment": "This method waits for an element matching `selector`, waits for actionability checks, then scrolls the element into view if needed and uses page.mouse to hover over the center of the element.\nIf there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried.", "returnComment": "Promise which resolves when the element matching `selector` is successfully hovered. Promise gets rejected if there's no element matching `selector`.", "required": true, "templates": [], @@ -7316,7 +7316,7 @@ "name": "Promise", "properties": {} }, - "comment": "This method fetches an element with `selector`, if element is not already unchecked, it scrolls it into view if needed, and then uses frame.click to click in the center of the element.\nIf there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried.", + "comment": "This method waits for an element matching `selector`, waits for actionability checks. Then, if the element is not already unchecked, this method scrolls the element into view and uses elementHandle.click to click in the center of the element.\nIf there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried.", "returnComment": "Promise which resolves when the element matching `selector` is successfully unchecked. The Promise will be rejected if there is no element matching `selector`.", "required": true, "templates": [], @@ -7425,7 +7425,7 @@ "kind": "property", "name": "arg", "type": { - "name": "Serializable|JSHandle", + "name": "EvaluationArgument", "properties": {} }, "comment": "Optional argument to pass to `pageFunction`", @@ -7772,7 +7772,7 @@ "kind": "property", "name": "arg", "type": { - "name": "Serializable|JSHandle", + "name": "EvaluationArgument", "properties": {} }, "comment": "Optional argument to pass to `pageFunction`", @@ -7822,7 +7822,7 @@ "kind": "property", "name": "arg", "type": { - "name": "Serializable|JSHandle", + "name": "EvaluationArgument", "properties": {} }, "comment": "Optional argument to pass to `pageFunction`", @@ -7901,7 +7901,7 @@ "name": "Promise", "properties": {} }, - "comment": "If element is not already checked, it scrolls it into view if needed, and then uses elementHandle.click to click in the center of the element.", + "comment": "This method waits for actionability checks. Then, if the element is not already checked, this method scrolls the element into view and uses elementHandle.click to click in the center of the element.", "returnComment": "Promise which resolves when the element is successfully checked. Promise gets rejected if the operation fails.", "required": true, "templates": [], @@ -7964,7 +7964,7 @@ "name": "Promise", "properties": {} }, - "comment": "This method scrolls element into view if needed, and then uses page.mouse to click in the center of the element.\nIf the element is detached from DOM, the method throws an error.", + "comment": "This method waits for actionability checks, then scrolls the element into view if needed and uses page.mouse to click in the center of the element.\nIf the element is detached from DOM, the method throws an error.", "returnComment": "Promise which resolves when the element is successfully clicked. Promise gets rejected if the element is detached from DOM.", "required": true, "templates": [], @@ -8125,7 +8125,7 @@ "name": "Promise", "properties": {} }, - "comment": "This method scrolls element into view if needed, and then uses page.mouse to click in the center of the element.\nIf the element is detached from DOM, the method throws an error.\nBear in mind that if the first click of the `dblclick()` triggers a navigation event, there will be an exception.\n\n**NOTE** `elementHandle.dblclick()` dispatches two `click` events and a single `dblclick` event.", + "comment": "This method waits for actionability checks, then scrolls the element into view if needed and uses page.mouse to double click in the center of the element.\nIf the element is detached from DOM, the method throws an error.\nBear in mind that if the first click of the `dblclick()` triggers a navigation event, there will be an exception.\n\n**NOTE** `elementHandle.dblclick()` dispatches two `click` events and a single `dblclick` event.", "returnComment": "Promise which resolves when the element is successfully double clicked. Promise gets rejected if the element is detached from DOM.", "required": true, "templates": [], @@ -8401,7 +8401,7 @@ "name": "Promise", "properties": {} }, - "comment": "This method scrolls element into view if needed, and then uses page.mouse to hover over the center of the element.\nIf the element is detached from DOM, the method throws an error.", + "comment": "This method waits for actionability checks, then scrolls the element into view if needed and uses page.mouse to hover over the center of the element.\nIf the element is detached from DOM, the method throws an error.", "returnComment": "Promise which resolves when the element is successfully hovered.", "required": true, "templates": [], @@ -9081,7 +9081,7 @@ "name": "Promise", "properties": {} }, - "comment": "If element is not already unchecked, it scrolls it into view if needed, and then uses elementHandle.click to click in the center of the element.", + "comment": "This method waits for actionability checks. Then, if the element is not already unchecked, this method scrolls the element into view and uses elementHandle.click to click in the center of the element.", "returnComment": "Promise which resolves when the element is successfully unchecked. Promise gets rejected if the operation fails.", "required": true, "templates": [], @@ -9191,7 +9191,7 @@ "kind": "property", "name": "arg", "type": { - "name": "Serializable|JSHandle", + "name": "EvaluationArgument", "properties": {} }, "comment": "Optional argument to pass to `pageFunction`", @@ -9229,7 +9229,7 @@ "kind": "property", "name": "arg", "type": { - "name": "Serializable|JSHandle", + "name": "EvaluationArgument", "properties": {} }, "comment": "Optional argument to pass to `pageFunction`", @@ -9350,7 +9350,7 @@ "kind": "property", "name": "arg", "type": { - "name": "Serializable|JSHandle", + "name": "EvaluationArgument", "properties": {} }, "comment": "Optional argument to pass to `pageFunction`", @@ -9388,7 +9388,7 @@ "kind": "property", "name": "arg", "type": { - "name": "Serializable|JSHandle", + "name": "EvaluationArgument", "properties": {} }, "comment": "Optional argument to pass to `pageFunction`", @@ -9481,9 +9481,9 @@ "name": "string", "properties": {} }, - "comment": "Optional URL of the resource if available.", + "comment": "URL of the resource if available, otherwise empty string.", "returnComment": "", - "required": false, + "required": true, "templates": [] }, "lineNumber": { @@ -9493,9 +9493,9 @@ "name": "number", "properties": {} }, - "comment": "Optional 0-based line number in the resource if available.", + "comment": "0-based line number in the resource.", "returnComment": "", - "required": false, + "required": true, "templates": [] }, "columnNumber": { @@ -9505,9 +9505,9 @@ "name": "number", "properties": {} }, - "comment": "Optional 0-based column number in the resource if available.", + "comment": "0-based column number in the resource.", "returnComment": "", - "required": false, + "required": true, "templates": [] } } @@ -11438,7 +11438,7 @@ "kind": "property", "name": "arg", "type": { - "name": "Serializable|JSHandle", + "name": "EvaluationArgument", "properties": {} }, "comment": "Optional argument to pass to `pageFunction`", @@ -11476,7 +11476,7 @@ "kind": "property", "name": "arg", "type": { - "name": "Serializable|JSHandle", + "name": "EvaluationArgument", "properties": {} }, "comment": "Optional argument to pass to `pageFunction`", diff --git a/driver/package.json b/driver/package.json index af51d7670..810f564f2 100644 --- a/driver/package.json +++ b/driver/package.json @@ -13,7 +13,7 @@ }, "license": "Apache-2.0", "dependencies": { - "playwright": "1.3.0-next.1596659749397" + "playwright": "1.3.0-next.1596843106133" }, "devDependencies": { "pkg": "^4.4.9" diff --git a/playwright/async_api.py b/playwright/async_api.py index b4ec806f5..323de3c25 100644 --- a/playwright/async_api.py +++ b/playwright/async_api.py @@ -944,7 +944,7 @@ async def hover( ) -> NoneType: """ElementHandle.hover - This method scrolls element into view if needed, and then uses page.mouse to hover over the center of the element. + This method waits for actionability checks, then scrolls the element into view if needed and uses page.mouse to hover over the center of the element. If the element is detached from DOM, the method throws an error. Parameters @@ -979,7 +979,7 @@ async def click( ) -> NoneType: """ElementHandle.click - This method scrolls element into view if needed, and then uses page.mouse to click in the center of the element. + This method waits for actionability checks, then scrolls the element into view if needed and uses page.mouse to click in the center of the element. If the element is detached from DOM, the method throws an error. Parameters @@ -1028,7 +1028,7 @@ async def dblclick( ) -> NoneType: """ElementHandle.dblclick - This method scrolls element into view if needed, and then uses page.mouse to click in the center of the element. + This method waits for actionability checks, then scrolls the element into view if needed and uses page.mouse to double click in the center of the element. If the element is detached from DOM, the method throws an error. Bear in mind that if the first click of the `dblclick()` triggers a navigation event, there will be an exception. @@ -1241,7 +1241,7 @@ async def check( ) -> NoneType: """ElementHandle.check - If element is not already checked, it scrolls it into view if needed, and then uses elementHandle.click to click in the center of the element. + This method waits for actionability checks. Then, if the element is not already checked, this method scrolls the element into view and uses elementHandle.click to click in the center of the element. Parameters ---------- @@ -1263,7 +1263,7 @@ async def uncheck( ) -> NoneType: """ElementHandle.uncheck - If element is not already unchecked, it scrolls it into view if needed, and then uses elementHandle.click to click in the center of the element. + This method waits for actionability checks. Then, if the element is not already unchecked, this method scrolls the element into view and uses elementHandle.click to click in the center of the element. Parameters ---------- @@ -2108,7 +2108,7 @@ async def click( ) -> NoneType: """Frame.click - This method fetches an element with `selector`, scrolls it into view if needed, and then uses page.mouse to click in the center of the element. + This method waits for an element matching `selector`, waits for actionability checks, then scrolls the element into view if needed and uses page.mouse to click in the center of the element. If there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried. Parameters @@ -2160,7 +2160,7 @@ async def dblclick( ) -> NoneType: """Frame.dblclick - This method fetches an element with `selector`, scrolls it into view if needed, and then uses page.mouse to double click in the center of the element. + This method waits for an element matching `selector`, waits for actionability checks, then scrolls the element into view if needed and uses page.mouse to double click in the center of the element. If there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried. Bear in mind that if the first click of the `dblclick()` triggers a navigation event, there will be an exception. @@ -2339,7 +2339,7 @@ async def hover( ) -> NoneType: """Frame.hover - This method fetches an element with `selector`, scrolls it into view if needed, and then uses page.mouse to hover over the center of the element. + This method waits for an element matching `selector`, waits for actionability checks, then scrolls the element into view if needed and uses page.mouse to hover over the center of the element. If there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried. Parameters @@ -2529,7 +2529,7 @@ async def check( ) -> NoneType: """Frame.check - This method fetches an element with `selector`, if element is not already checked, it scrolls it into view if needed, and then uses frame.click to click in the center of the element. + This method waits for an element matching `selector`, waits for actionability checks. Then, if the element is not already checked, this method scrolls the element into view and uses elementHandle.click to click in the center of the element. If there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried. Parameters @@ -2558,7 +2558,7 @@ async def uncheck( ) -> NoneType: """Frame.uncheck - This method fetches an element with `selector`, if element is not already unchecked, it scrolls it into view if needed, and then uses frame.click to click in the center of the element. + This method waits for an element matching `selector`, waits for actionability checks. Then, if the element is not already unchecked, this method scrolls the element into view and uses elementHandle.click to click in the center of the element. If there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried. Parameters @@ -4068,7 +4068,7 @@ async def click( ) -> NoneType: """Page.click - This method fetches an element with `selector`, scrolls it into view if needed, and then uses page.mouse to click in the center of the element. + This method waits for an element matching `selector`, waits for actionability checks, then scrolls the element into view if needed and uses page.mouse to click in the center of the element. If there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried. Shortcut for page.mainFrame().click(selector[, options]). @@ -4121,7 +4121,7 @@ async def dblclick( ) -> NoneType: """Page.dblclick - This method fetches an element with `selector`, scrolls it into view if needed, and then uses page.mouse to double click in the center of the element. + This method waits for an element matching `selector`, waits for actionability checks, then scrolls the element into view if needed and uses page.mouse to double click in the center of the element. If there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried. Bear in mind that if the first click of the `dblclick()` triggers a navigation event, there will be an exception. @@ -4304,7 +4304,7 @@ async def hover( ) -> NoneType: """Page.hover - This method fetches an element with `selector`, scrolls it into view if needed, and then uses page.mouse to hover over the center of the element. + This method waits for an element matching `selector`, waits for actionability checks, then scrolls the element into view if needed and uses page.mouse to hover over the center of the element. If there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried. Shortcut for page.mainFrame().hover(selector[, options]). @@ -4494,7 +4494,7 @@ async def check( ) -> NoneType: """Page.check - This method fetches an element with `selector`, if element is not already checked, it scrolls it into view if needed, and then uses page.click to click in the center of the element. + This method waits for an element matching `selector`, waits for actionability checks. Then, if the element is not already checked, this method scrolls the element into view and uses elementHandle.click to click in the center of the element. If there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried. Shortcut for page.mainFrame().check(selector[, options]). @@ -4524,7 +4524,7 @@ async def uncheck( ) -> NoneType: """Page.uncheck - This method fetches an element with `selector`, if element is not already unchecked, it scrolls it into view if needed, and then uses page.click to click in the center of the element. + This method waits for an element matching `selector`, waits for actionability checks. Then, if the element is not already unchecked, this method scrolls the element into view and uses elementHandle.click to click in the center of the element. If there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried. Shortcut for page.mainFrame().uncheck(selector[, options]). @@ -4574,7 +4574,7 @@ async def waitForFunction( The `waitForFunction` can be used to observe viewport size change: To pass an argument from Node.js to the predicate of `page.waitForFunction` function: - Shortcut for [page.mainFrame().waitForFunction(pageFunction, arg, options]])](#framewaitforfunctionpagefunction-arg-options). + Shortcut for page.mainFrame().waitForFunction(pageFunction[, arg, options]). Parameters ---------- diff --git a/playwright/drivers/browsers.json b/playwright/drivers/browsers.json index 839fd9f18..f6ac44fb9 100644 --- a/playwright/drivers/browsers.json +++ b/playwright/drivers/browsers.json @@ -8,7 +8,7 @@ }, { "name": "firefox", - "revision": "1144", + "revision": "1154", "download": true }, { diff --git a/playwright/page.py b/playwright/page.py index 7bf024cc2..45ae02bed 100644 --- a/playwright/page.py +++ b/playwright/page.py @@ -539,8 +539,15 @@ async def screenshot( fullPage: bool = None, clip: FloatRect = None, ) -> bytes: - binary = await self._channel.send("screenshot", locals_to_params(locals())) - return base64.b64decode(binary) + params = locals_to_params(locals()) + if "path" in params: + del params["path"] + encoded_binary = await self._channel.send("screenshot", params) + decoded_binary = base64.b64decode(encoded_binary) + if path: + with open(path, "wb") as fd: + fd.write(decoded_binary) + return decoded_binary async def title(self) -> str: return await self._main_frame.title() @@ -722,7 +729,8 @@ async def pdf( path: str = None, ) -> bytes: params = locals_to_params(locals()) - del params["path"] + if "path" in params: + del params["path"] encoded_binary = await self._channel.send("pdf", params) decoded_binary = base64.b64decode(encoded_binary) if path: diff --git a/playwright/sync_api.py b/playwright/sync_api.py index b8fc47675..ad9a2363a 100644 --- a/playwright/sync_api.py +++ b/playwright/sync_api.py @@ -968,7 +968,7 @@ def hover( ) -> NoneType: """ElementHandle.hover - This method scrolls element into view if needed, and then uses page.mouse to hover over the center of the element. + This method waits for actionability checks, then scrolls the element into view if needed and uses page.mouse to hover over the center of the element. If the element is detached from DOM, the method throws an error. Parameters @@ -1005,7 +1005,7 @@ def click( ) -> NoneType: """ElementHandle.click - This method scrolls element into view if needed, and then uses page.mouse to click in the center of the element. + This method waits for actionability checks, then scrolls the element into view if needed and uses page.mouse to click in the center of the element. If the element is detached from DOM, the method throws an error. Parameters @@ -1056,7 +1056,7 @@ def dblclick( ) -> NoneType: """ElementHandle.dblclick - This method scrolls element into view if needed, and then uses page.mouse to click in the center of the element. + This method waits for actionability checks, then scrolls the element into view if needed and uses page.mouse to double click in the center of the element. If the element is detached from DOM, the method throws an error. Bear in mind that if the first click of the `dblclick()` triggers a navigation event, there will be an exception. @@ -1285,7 +1285,7 @@ def check( ) -> NoneType: """ElementHandle.check - If element is not already checked, it scrolls it into view if needed, and then uses elementHandle.click to click in the center of the element. + This method waits for actionability checks. Then, if the element is not already checked, this method scrolls the element into view and uses elementHandle.click to click in the center of the element. Parameters ---------- @@ -1309,7 +1309,7 @@ def uncheck( ) -> NoneType: """ElementHandle.uncheck - If element is not already unchecked, it scrolls it into view if needed, and then uses elementHandle.click to click in the center of the element. + This method waits for actionability checks. Then, if the element is not already unchecked, this method scrolls the element into view and uses elementHandle.click to click in the center of the element. Parameters ---------- @@ -2186,7 +2186,7 @@ def click( ) -> NoneType: """Frame.click - This method fetches an element with `selector`, scrolls it into view if needed, and then uses page.mouse to click in the center of the element. + This method waits for an element matching `selector`, waits for actionability checks, then scrolls the element into view if needed and uses page.mouse to click in the center of the element. If there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried. Parameters @@ -2240,7 +2240,7 @@ def dblclick( ) -> NoneType: """Frame.dblclick - This method fetches an element with `selector`, scrolls it into view if needed, and then uses page.mouse to double click in the center of the element. + This method waits for an element matching `selector`, waits for actionability checks, then scrolls the element into view if needed and uses page.mouse to double click in the center of the element. If there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried. Bear in mind that if the first click of the `dblclick()` triggers a navigation event, there will be an exception. @@ -2428,7 +2428,7 @@ def hover( ) -> NoneType: """Frame.hover - This method fetches an element with `selector`, scrolls it into view if needed, and then uses page.mouse to hover over the center of the element. + This method waits for an element matching `selector`, waits for actionability checks, then scrolls the element into view if needed and uses page.mouse to hover over the center of the element. If there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried. Parameters @@ -2631,7 +2631,7 @@ def check( ) -> NoneType: """Frame.check - This method fetches an element with `selector`, if element is not already checked, it scrolls it into view if needed, and then uses frame.click to click in the center of the element. + This method waits for an element matching `selector`, waits for actionability checks. Then, if the element is not already checked, this method scrolls the element into view and uses elementHandle.click to click in the center of the element. If there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried. Parameters @@ -2665,7 +2665,7 @@ def uncheck( ) -> NoneType: """Frame.uncheck - This method fetches an element with `selector`, if element is not already unchecked, it scrolls it into view if needed, and then uses frame.click to click in the center of the element. + This method waits for an element matching `selector`, waits for actionability checks. Then, if the element is not already unchecked, this method scrolls the element into view and uses elementHandle.click to click in the center of the element. If there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried. Parameters @@ -4238,7 +4238,7 @@ def click( ) -> NoneType: """Page.click - This method fetches an element with `selector`, scrolls it into view if needed, and then uses page.mouse to click in the center of the element. + This method waits for an element matching `selector`, waits for actionability checks, then scrolls the element into view if needed and uses page.mouse to click in the center of the element. If there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried. Shortcut for page.mainFrame().click(selector[, options]). @@ -4293,7 +4293,7 @@ def dblclick( ) -> NoneType: """Page.dblclick - This method fetches an element with `selector`, scrolls it into view if needed, and then uses page.mouse to double click in the center of the element. + This method waits for an element matching `selector`, waits for actionability checks, then scrolls the element into view if needed and uses page.mouse to double click in the center of the element. If there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried. Bear in mind that if the first click of the `dblclick()` triggers a navigation event, there will be an exception. @@ -4485,7 +4485,7 @@ def hover( ) -> NoneType: """Page.hover - This method fetches an element with `selector`, scrolls it into view if needed, and then uses page.mouse to hover over the center of the element. + This method waits for an element matching `selector`, waits for actionability checks, then scrolls the element into view if needed and uses page.mouse to hover over the center of the element. If there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried. Shortcut for page.mainFrame().hover(selector[, options]). @@ -4688,7 +4688,7 @@ def check( ) -> NoneType: """Page.check - This method fetches an element with `selector`, if element is not already checked, it scrolls it into view if needed, and then uses page.click to click in the center of the element. + This method waits for an element matching `selector`, waits for actionability checks. Then, if the element is not already checked, this method scrolls the element into view and uses elementHandle.click to click in the center of the element. If there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried. Shortcut for page.mainFrame().check(selector[, options]). @@ -4723,7 +4723,7 @@ def uncheck( ) -> NoneType: """Page.uncheck - This method fetches an element with `selector`, if element is not already unchecked, it scrolls it into view if needed, and then uses page.click to click in the center of the element. + This method waits for an element matching `selector`, waits for actionability checks. Then, if the element is not already unchecked, this method scrolls the element into view and uses elementHandle.click to click in the center of the element. If there's no element matching `selector`, the method waits until a matching element appears in the DOM. If the element is detached during the actionability checks, the action is retried. Shortcut for page.mainFrame().uncheck(selector[, options]). @@ -4778,7 +4778,7 @@ def waitForFunction( The `waitForFunction` can be used to observe viewport size change: To pass an argument from Node.js to the predicate of `page.waitForFunction` function: - Shortcut for [page.mainFrame().waitForFunction(pageFunction, arg, options]])](#framewaitforfunctionpagefunction-arg-options). + Shortcut for page.mainFrame().waitForFunction(pageFunction[, arg, options]). Parameters ---------- diff --git a/tests/async/test_browser.py b/tests/async/test_browser.py index 167a09f20..9baa18087 100644 --- a/tests/async/test_browser.py +++ b/tests/async/test_browser.py @@ -47,4 +47,4 @@ async def test_version_should_work(browser: Browser, is_chromium): if is_chromium: assert re.match(r"^\d+\.\d+\.\d+\.\d+$", version) else: - assert re.match(r"^\d+\.\d+$", version) + assert re.match(r"^\d+\.\d+", version) diff --git a/tests/async/test_browsercontext_add_cookies.py b/tests/async/test_browsercontext_add_cookies.py index 19e026cfc..63d7dd855 100644 --- a/tests/async/test_browsercontext_add_cookies.py +++ b/tests/async/test_browsercontext_add_cookies.py @@ -349,9 +349,7 @@ 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, is_chromium, is_firefox -): +async def test_should_not_block_third_party_cookies(context, page, server, is_chromium): await page.goto(server.EMPTY_PAGE) await page.evaluate( """src => { @@ -367,7 +365,7 @@ async def test_should_not_block_third_party_cookies( ) await page.frames[1].evaluate("document.cookie = 'username=John Doe'") await page.waitForTimeout(2000) - allows_third_party = is_chromium or is_firefox + allows_third_party = is_chromium cookies = await context.cookies(server.CROSS_PROCESS_PREFIX + "/grid.html") if allows_third_party: diff --git a/tests/async/test_browsercontext_cookies.py b/tests/async/test_browsercontext_cookies.py index 4c27e87fc..d2e868208 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): +async def test_should_get_a_cookie(context, page, server, is_firefox): await page.goto(server.EMPTY_PAGE) document_cookie = await page.evaluate( """() => { @@ -39,12 +39,12 @@ async def test_should_get_a_cookie(context, page, server): "expires": -1, "httpOnly": False, "secure": False, - "sameSite": "None", + "sameSite": "Lax" if is_firefox else "None", } ] -async def test_should_get_a_non_session_cookie(context, page, server): +async def test_should_get_a_non_session_cookie(context, page, server, is_firefox): await page.goto(server.EMPTY_PAGE) # @see https://en.wikipedia.org/wiki/Year_2038_problem date = int(datetime.datetime(2038, 1, 1).timestamp() * 1000) @@ -66,7 +66,7 @@ async def test_should_get_a_non_session_cookie(context, page, server): "expires": date / 1000, "httpOnly": False, "secure": False, - "sameSite": "None", + "sameSite": "Lax" if is_firefox else "None", } ] @@ -121,7 +121,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): +async def test_should_get_multiple_cookies(context, page, server, is_firefox): await page.goto(server.EMPTY_PAGE) document_cookie = await page.evaluate( """() => { @@ -142,7 +142,7 @@ async def test_should_get_multiple_cookies(context, page, server): "expires": -1, "httpOnly": False, "secure": False, - "sameSite": "None", + "sameSite": "Lax" if is_firefox else "None", }, { "name": "username", @@ -152,7 +152,7 @@ async def test_should_get_multiple_cookies(context, page, server): "expires": -1, "httpOnly": False, "secure": False, - "sameSite": "None", + "sameSite": "Lax" if is_firefox else "None", }, ] diff --git a/tests/async/test_defaultbrowsercontext.py b/tests/async/test_defaultbrowsercontext.py index 4ff816e6e..99af57582 100644 --- a/tests/async/test_defaultbrowsercontext.py +++ b/tests/async/test_defaultbrowsercontext.py @@ -37,7 +37,7 @@ async def _launch(**options): await context.close() -async def test_context_cookies_should_work(server, launch_persistent): +async def test_context_cookies_should_work(server, launch_persistent, is_firefox): (page, context) = await launch_persistent() await page.goto(server.EMPTY_PAGE) document_cookie = await page.evaluate( @@ -57,7 +57,7 @@ async def test_context_cookies_should_work(server, launch_persistent): "expires": -1, "httpOnly": False, "secure": False, - "sameSite": "None", + "sameSite": "Lax" if is_firefox else "None", } ] @@ -100,7 +100,7 @@ async def test_context_clear_cookies_should_work(server, launch_persistent): async def test_should_not_block_third_party_cookies( - server, launch_persistent, is_chromium, is_firefox + server, launch_persistent, is_chromium ): (page, context) = await launch_persistent() await page.goto(server.EMPTY_PAGE) @@ -124,7 +124,7 @@ async def test_should_not_block_third_party_cookies( ) await page.waitForTimeout(2000) - allows_third_party = is_chromium or is_firefox + allows_third_party = is_chromium assert document_cookie == ("username=John Doe" if allows_third_party else "") cookies = await context.cookies(server.CROSS_PROCESS_PREFIX + "/grid.html") if allows_third_party: diff --git a/tests/async/test_headful.py b/tests/async/test_headful.py index 3bdb50c85..2a8e8f4c3 100644 --- a/tests/async/test_headful.py +++ b/tests/async/test_headful.py @@ -131,7 +131,7 @@ async def test_should_not_block_third_party_cookies( ) await page.waitForTimeout(2000) - allowsThirdParty = is_chromium or is_firefox + allowsThirdParty = is_chromium assert document_cookie == ("username=John Doe" if allowsThirdParty else "") cookies = await page.context.cookies(server.CROSS_PROCESS_PREFIX + "/grid.html") if allowsThirdParty: diff --git a/tests/async/test_navigation.py b/tests/async/test_navigation.py index 5c02712e9..e629ed5b5 100644 --- a/tests/async/test_navigation.py +++ b/tests/async/test_navigation.py @@ -133,6 +133,7 @@ async def test_goto_should_return_response_when_page_changes_its_url_after_load( assert response.status == 200 +@pytest.mark.skip_browser("firefox") async def test_goto_should_work_with_subframes_return_204(page, server): def handle(request): request.setResponseCode(204) @@ -554,6 +555,7 @@ async def test_wait_for_nav_should_work_with_dom_history_back_forward(page, serv assert page.url == server.PREFIX + "/second.html" +@pytest.mark.skip_browser("firefox") async def test_wait_for_nav_should_work_when_subframe_issues_window_stop(page, server): server.set_route("/frames/style.css", lambda _: None) navigation_promise = asyncio.create_task( diff --git a/tests/async/test_pdf.py b/tests/async/test_pdf.py index 8e414ad9f..a94efb92f 100644 --- a/tests/async/test_pdf.py +++ b/tests/async/test_pdf.py @@ -25,3 +25,9 @@ async def test_should_be_able_to_save_pdf_file(page: Page, server, tmpdir: Path) output_file = tmpdir / "foo.png" await page.pdf(path=str(output_file)) assert os.path.getsize(output_file) > 0 + + +@pytest.mark.only_browser("chromium") +async def test_should_be_able_capture_pdf_without_path(page: Page): + buffer = await page.pdf() + assert buffer diff --git a/tests/sync/test_pdf.py b/tests/sync/test_pdf.py index 196129892..f6d081880 100644 --- a/tests/sync/test_pdf.py +++ b/tests/sync/test_pdf.py @@ -25,3 +25,9 @@ def test_should_be_able_to_save_pdf_file(page: Page, server, tmpdir: Path): output_file = tmpdir / "foo.png" page.pdf(path=str(output_file)) assert os.path.getsize(output_file) > 0 + + +@pytest.mark.only_browser("chromium") +def test_should_be_able_capture_pdf_without_path(page: Page): + buffer = page.pdf() + assert buffer