diff --git a/playwright/browser_context.py b/playwright/browser_context.py index cee44981d..b24ce9a9d 100644 --- a/playwright/browser_context.py +++ b/playwright/browser_context.py @@ -27,6 +27,7 @@ TimeoutSettings, URLMatch, URLMatcher, + locals_to_params, ) from playwright.network import Request, Route, serialize_headers from playwright.page import BindingCall, Page @@ -119,15 +120,13 @@ async def clearCookies(self) -> None: async def grantPermissions( self, permissions: List[str], origin: str = None ) -> None: - await self._channel.send( - "grantPermissions", dict(permissions=permissions, origin=origin) - ) + await self._channel.send("grantPermissions", locals_to_params(locals())) async def clearPermissions(self) -> None: await self._channel.send("clearPermissions") async def setGeolocation(self, geolocation: Optional[Dict]) -> None: - await self._channel.send("setGeolocation", dict(geolocation=geolocation)) + await self._channel.send("setGeolocation", locals_to_params(locals())) async def setExtraHTTPHeaders(self, headers: Dict) -> None: await self._channel.send( diff --git a/scripts/documentation_provider.py b/scripts/documentation_provider.py index 2a065e32e..390793dee 100644 --- a/scripts/documentation_provider.py +++ b/scripts/documentation_provider.py @@ -76,13 +76,13 @@ def print_entry( if not doc_value and "options" in args: args = args["options"]["type"]["properties"] doc_value = args.get(name) - if not doc_value and fqname == "Route.fulfill": + elif not doc_value and fqname == "Route.fulfill": args = args["response"]["type"]["properties"] doc_value = args.get(name) - if not doc_value and fqname == "Route.continue": + elif not doc_value and fqname == "Route.continue": args = args["overrides"]["type"]["properties"] doc_value = args.get(name) - if not doc_value and fqname == "Page.setViewportSize": + elif not doc_value and fqname == "Page.setViewportSize": args = args["viewportSize"]["type"]["properties"] doc_value = args.get(name) if not doc_value: diff --git a/tests/assets/geolocation.html b/tests/assets/geolocation.html new file mode 100644 index 000000000..3d44c3f7f --- /dev/null +++ b/tests/assets/geolocation.html @@ -0,0 +1,7 @@ + diff --git a/tests/async/test_geolocation.py b/tests/async/test_geolocation.py new file mode 100644 index 000000000..b9ea160c2 --- /dev/null +++ b/tests/async/test_geolocation.py @@ -0,0 +1,146 @@ +# Copyright (c) Microsoft Corporation. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + + +import asyncio + +import pytest + +from playwright.async_api import BrowserContext, Page +from playwright.helper import Error + + +async def test_should_work(page: Page, server, context: BrowserContext): + await context.grantPermissions(["geolocation"]) + await page.goto(server.EMPTY_PAGE) + await context.setGeolocation({"longitude": 10, "latitude": 10}) + geolocation = await page.evaluate( + """() => new Promise(resolve => navigator.geolocation.getCurrentPosition(position => { + resolve({latitude: position.coords.latitude, longitude: position.coords.longitude}); + }))""" + ) + assert geolocation == {"latitude": 10, "longitude": 10} + + +async def test_should_throw_when_invalid_longitude(context): + with pytest.raises(Error) as exc: + await context.setGeolocation({"longitude": 200, "latitude": 10}) + assert ( + "geolocation.longitude: precondition -180 <= LONGITUDE <= 180 failed." + in exc.value.message + ) + + +async def test_should_isolate_contexts(page, server, context, browser): + await context.grantPermissions(["geolocation"]) + await context.setGeolocation({"longitude": 10, "latitude": 10}) + await page.goto(server.EMPTY_PAGE) + + context2 = await browser.newContext( + permissions=["geolocation"], geolocation={"longitude": 20, "latitude": 20} + ) + + page2 = await context2.newPage() + await page2.goto(server.EMPTY_PAGE) + + geolocation = await page.evaluate( + """() => new Promise(resolve => navigator.geolocation.getCurrentPosition(position => { + resolve({latitude: position.coords.latitude, longitude: position.coords.longitude}) + }))""" + ) + assert geolocation == {"latitude": 10, "longitude": 10} + + geolocation2 = await page2.evaluate( + """() => new Promise(resolve => navigator.geolocation.getCurrentPosition(position => { + resolve({latitude: position.coords.latitude, longitude: position.coords.longitude}) + }))""" + ) + assert geolocation2 == {"latitude": 20, "longitude": 20} + + await context2.close() + + +async def test_should_throw_with_missing_latitude(context): + with pytest.raises(Error) as exc: + await context.setGeolocation({"longitude": 10}) + "geolocation.latitude: expected number, got undefined" in exc.value.message + + +async def test_should_throw_with_missing_longitude_in_default_options(browser): + with pytest.raises(Error) as exc: + context = await browser.newContext(geolocation={"latitude": 10}) + await context.close() + assert "geolocation.longitude: expected number, got undefined" in exc.value.message + + +async def test_should_use_context_options(browser, server): + options = { + "geolocation": {"longitude": 10, "latitude": 10}, + "permissions": ["geolocation"], + } + context = await browser.newContext(**options) + page = await context.newPage() + await page.goto(server.EMPTY_PAGE) + + geolocation = await page.evaluate( + """() => new Promise(resolve => navigator.geolocation.getCurrentPosition(position => { + resolve({latitude: position.coords.latitude, longitude: position.coords.longitude}); + }))""" + ) + assert geolocation == {"latitude": 10, "longitude": 10} + await context.close() + + +async def test_watchPosition_should_be_notified(page, server, context): + await context.grantPermissions(["geolocation"]) + await page.goto(server.EMPTY_PAGE) + messages = [] + page.on("console", lambda message: messages.append(message.text)) + + await context.setGeolocation({"latitude": 0, "longitude": 0}) + await page.evaluate( + """() => { + navigator.geolocation.watchPosition(pos => { + const coords = pos.coords; + console.log(`lat=${coords.latitude} lng=${coords.longitude}`); + }, err => {}); + }""" + ) + + await context.setGeolocation({"latitude": 0, "longitude": 10}) + await page.waitForEvent("console", lambda message: "lat=0 lng=10" in message.text) + await context.setGeolocation({"latitude": 20, "longitude": 30}) + await page.waitForEvent("console", lambda message: "lat=20 lng=30" in message.text) + await context.setGeolocation({"latitude": 40, "longitude": 50}) + await page.waitForEvent("console", lambda message: "lat=40 lng=50" in message.text) + + allMessages = "|".join(messages) + "lat=0 lng=10" in allMessages + "lat=20 lng=30" in allMessages + "lat=40 lng=50" in allMessages + + +async def test_should_use_context_options_for_popup(page, context, server): + await context.grantPermissions(["geolocation"]) + await context.setGeolocation({"longitude": 10, "latitude": 10}) + [popup, _] = await asyncio.gather( + page.waitForEvent("popup"), + page.evaluate( + "url => window._popup = window.open(url)", + server.PREFIX + "/geolocation.html", + ), + ) + await popup.waitForLoadState() + geolocation = await popup.evaluate("() => window.geolocationPromise") + assert geolocation == {"longitude": 10, "latitude": 10} diff --git a/tests/sync/test_pdf.py b/tests/sync/test_pdf.py new file mode 100644 index 000000000..196129892 --- /dev/null +++ b/tests/sync/test_pdf.py @@ -0,0 +1,27 @@ +# Copyright (c) Microsoft Corporation. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +import os +from pathlib import Path + +import pytest + +from playwright.page import Page + + +@pytest.mark.only_browser("chromium") +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