'
- )
- await page.click("text=Click target")
- assert await page.evaluate("window.__CLICKED")
-
-
-async def test_wait_for_BUTTON_to_be_clickable_when_it_has_pointer_events_none(
- page: Page,
-) -> None:
- await page.set_content(
- '
Click target '
- )
- done = []
-
- async def click() -> None:
- await page.click("text=Click target")
- done.append(True)
-
- click_promise = asyncio.create_task(click())
- await give_it_a_chance_to_click(page)
- assert await page.evaluate("window.__CLICKED") is None
- assert done == []
- await page.evaluate(
- "document.querySelector('button').style.removeProperty('pointer-events')"
- )
- await click_promise
- assert await page.evaluate("window.__CLICKED")
-
-
-async def test_wait_for_LABEL_to_be_clickable_when_it_has_pointer_events_none(
- page: Page,
-) -> None:
- await page.set_content(
- '
Click target '
- )
- click_promise = asyncio.create_task(page.click("text=Click target"))
- # Do a few roundtrips to the page.
- for _ in range(5):
- assert await page.evaluate("window.__CLICKED") is None
- # remove 'pointer-events: none' css from button.
- await page.evaluate(
- "document.querySelector('label').style.removeProperty('pointer-events')"
- )
- await click_promise
- assert await page.evaluate("window.__CLICKED")
-
-
-async def test_update_modifiers_correctly(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/button.html")
- await page.click("button", modifiers=["Shift"])
- assert await page.evaluate("shiftKey")
- await page.click("button", modifiers=[])
- assert await page.evaluate("shiftKey") is False
-
- await page.keyboard.down("Shift")
- await page.click("button", modifiers=[])
- assert await page.evaluate("shiftKey") is False
- await page.click("button")
- assert await page.evaluate("shiftKey")
- await page.keyboard.up("Shift")
- await page.click("button")
- assert await page.evaluate("shiftKey") is False
-
-
-async def test_click_an_offscreen_element_when_scroll_behavior_is_smooth(
- page: Page,
-) -> None:
- await page.set_content(
- """
-
- hi
-
- """
- )
- await page.click("button")
- assert await page.evaluate("window.clicked")
-
-
-async def test_report_nice_error_when_element_is_detached_and_force_clicked(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/input/animating-button.html")
- await page.evaluate("addButton()")
- handle = await page.query_selector("button")
- assert handle
- await page.evaluate("stopButton(true)")
- error: Optional[Error] = None
- try:
- await handle.click(force=True)
- except Error as e:
- error = e
- assert await page.evaluate("window.clicked") is None
- assert error
- assert "Element is not attached to the DOM" in error.message
-
-
-async def test_fail_when_element_detaches_after_animation(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/input/animating-button.html")
- await page.evaluate("addButton()")
- handle = await page.query_selector("button")
- assert handle
- promise = asyncio.create_task(handle.click())
- await asyncio.sleep(0) # execute scheduled tasks, but don't await them
- await page.evaluate("stopButton(true)")
- with pytest.raises(Error) as exc_info:
- await promise
- assert await page.evaluate("window.clicked") is None
- assert "Element is not attached to the DOM" in exc_info.value.message
-
-
-async def test_retry_when_element_detaches_after_animation(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/input/animating-button.html")
- await page.evaluate("addButton()")
- clicked = []
-
- async def click() -> None:
- await page.click("button")
- clicked.append(True)
-
- promise = asyncio.create_task(click())
- await asyncio.sleep(0) # execute scheduled tasks, but don't await them
- assert clicked == []
- assert await page.evaluate("window.clicked") is None
- await page.evaluate("stopButton(true)")
- await page.evaluate("addButton()")
- assert clicked == []
- assert await page.evaluate("window.clicked") is None
- await page.evaluate("stopButton(true)")
- await page.evaluate("addButton()")
- assert clicked == []
- assert await page.evaluate("window.clicked") is None
- await page.evaluate("stopButton(false)")
- await promise
- assert clicked == [True]
- assert await page.evaluate("window.clicked")
-
-
-async def test_retry_when_element_is_animating_from_outside_the_viewport(
- page: Page, server: Server
-) -> None:
- await page.set_content(
- """
-
-
-
- """
- )
- handle = await page.query_selector("button")
- assert handle
- promise = asyncio.create_task(handle.click())
- await asyncio.sleep(0) # execute scheduled tasks, but don't await them
- await handle.evaluate("button => button.className = 'animated'")
- await promise
- assert await page.evaluate("window.clicked")
-
-
-async def test_fail_when_element_is_animating_from_outside_the_viewport_with_force(
- page: Page,
-) -> None:
- await page.set_content(
- """
-
-
-
- """
- )
- handle = await page.query_selector("button")
- assert handle
- promise = asyncio.create_task(handle.click(force=True))
- await asyncio.sleep(0) # execute scheduled tasks, but don't await them
- await handle.evaluate("button => button.className = 'animated'")
- error: Optional[Error] = None
- try:
- await promise
- except Error as e:
- error = e
- assert await page.evaluate("window.clicked") is None
- assert error
- assert "Element is outside of the viewport" in error.message
-
-
-async def test_not_retarget_when_element_changes_on_hover(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/react.html")
- await page.evaluate(
- """() => {
- renderComponent(e('div', {}, [e(MyButton, { name: 'button1', renameOnHover: true }), e(MyButton, { name: 'button2' })] ));
- }"""
- )
- await page.click("text=button1")
- assert await page.evaluate("window.button1")
- assert await page.evaluate("window.button2") is None
-
-
-async def test_not_retarget_when_element_is_recycled_on_hover(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/react.html")
- await page.evaluate(
- """() => {
- function shuffle() {
- renderComponent(e('div', {}, [e(MyButton, { name: 'button2' }), e(MyButton, { name: 'button1' })] ));
- }
- renderComponent(e('div', {}, [e(MyButton, { name: 'button1', onHover: shuffle }), e(MyButton, { name: 'button2' })] ));
- }"""
- )
-
- await page.click("text=button1")
- assert await page.evaluate("window.button1") is None
- assert await page.evaluate("window.button2")
-
-
-async def test_click_the_button_when_window_inner_width_is_corrupted(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/input/button.html")
- await page.evaluate("window.innerWidth = 0")
- await page.click("button")
- assert await page.evaluate("result") == "Clicked"
-
-
-async def test_timeout_when_click_opens_alert(page: Page, server: Server) -> None:
- await page.set_content('
Click me
')
- async with page.expect_event("dialog") as dialog_info:
- with pytest.raises(Error) as exc_info:
- await page.click("div", timeout=3000)
- assert "Timeout 3000ms exceeded" in exc_info.value.message
- dialog = await dialog_info.value
- await dialog.dismiss()
-
-
-async def test_check_the_box(page: Page) -> None:
- await page.set_content('
')
- await page.check("input")
- assert await page.evaluate("checkbox.checked")
-
-
-async def test_not_check_the_checked_box(page: Page) -> None:
- await page.set_content('
')
- await page.check("input")
- assert await page.evaluate("checkbox.checked")
-
-
-async def test_uncheck_the_box(page: Page) -> None:
- await page.set_content('
')
- await page.uncheck("input")
- assert await page.evaluate("checkbox.checked") is False
-
-
-async def test_not_uncheck_the_unchecked_box(page: Page) -> None:
- await page.set_content('
')
- await page.uncheck("input")
- assert await page.evaluate("checkbox.checked") is False
-
-
-async def test_check_the_box_by_label(page: Page) -> None:
- await page.set_content(
- '
'
- )
- await page.check("label")
- assert await page.evaluate("checkbox.checked")
-
-
-async def test_check_the_box_outside_label(page: Page) -> None:
- await page.set_content(
- '
Text
'
- )
- await page.check("label")
- assert await page.evaluate("checkbox.checked")
-
-
-async def test_check_the_box_inside_label_without_id(page: Page) -> None:
- await page.set_content(
- '
Text '
- )
- await page.check("label")
- assert await page.evaluate("checkbox.checked")
-
-
-async def test_check_radio(page: Page) -> None:
- await page.set_content(
- """
-
one
-
two
-
three"""
- )
- await page.check("#two")
- assert await page.evaluate("two.checked")
-
-
-async def test_check_the_box_by_aria_role(page: Page) -> None:
- await page.set_content(
- """
CHECKBOX
- """
- )
- await page.check("div")
- assert await page.evaluate("checkbox.getAttribute ('aria-checked')")
diff --git a/tests/async/test_console.py b/tests/async/test_console.py
deleted file mode 100644
index 7772523..0000000
--- a/tests/async/test_console.py
+++ /dev/null
@@ -1,152 +0,0 @@
-# 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.
-
-from typing import List
-
-import pytest
-from playwright.async_api import ConsoleMessage, Page
-
-from tests.server import Server
-
-
-async def test_console_should_work(page: Page, browser_name: str) -> None:
- messages: List[ConsoleMessage] = []
- page.once("console", lambda m: messages.append(m))
- async with page.expect_console_message() as message_info:
- await page.evaluate('() => console.log("hello", 5, {foo: "bar"})')
- message = await message_info.value
- if browser_name != "firefox":
- assert message.text == "hello 5 {foo: bar}"
- assert str(message) == "hello 5 {foo: bar}"
- else:
- assert message.text == "hello 5 JSHandle@object"
- assert str(message) == "hello 5 JSHandle@object"
- assert message.type == "log"
- assert await message.args[0].json_value() == "hello"
- assert await message.args[1].json_value() == 5
- assert await message.args[2].json_value() == {"foo": "bar"}
-
-
-async def test_console_should_emit_same_log_twice(page: Page) -> None:
- messages = []
- page.on("console", lambda m: messages.append(m.text))
- await page.evaluate('() => { for (let i = 0; i < 2; ++i ) console.log("hello"); } ')
- assert messages == ["hello", "hello"]
-
-
-async def test_console_should_use_text_for__str__(page: Page) -> None:
- messages = []
- page.on("console", lambda m: messages.append(m))
- await page.evaluate('() => console.log("Hello world")')
- assert len(messages) == 1
- assert str(messages[0]) == "Hello world"
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_console_should_work_for_different_console_api_calls(page: Page) -> None:
- messages: List[ConsoleMessage] = []
- page.on("console", lambda m: messages.append(m))
- # All console events will be reported before 'page.evaluate' is finished.
- await page.evaluate(
- """() => {
- // A pair of time/timeEnd generates only one Console API call.
- console.time('calling console.time');
- console.timeEnd('calling console.time');
- console.trace('calling console.trace');
- console.dir('calling console.dir');
- console.warn('calling console.warn');
- console.error('calling console.error');
- console.log(Promise.resolve('should not wait until resolved!'));
- }"""
- )
- assert list(map(lambda msg: msg.type, messages)) == [
- "timeEnd",
- "trace",
- "dir",
- "warning",
- "error",
- "log",
- ]
-
- assert "calling console.time" in messages[0].text
- assert list(map(lambda msg: msg.text, messages[1:])) == [
- "calling console.trace",
- "calling console.dir",
- "calling console.warn",
- "calling console.error",
- "Promise",
- ]
-
-
-async def test_console_should_not_fail_for_window_object(page: Page, browser_name: str) -> None:
- async with page.expect_console_message() as message_info:
- await page.evaluate("console.error(window)")
- message = await message_info.value
- if browser_name != "firefox":
- assert message.text == "Window"
- else:
- assert message.text == "JSHandle@object"
-
-
-# Upstream issue https://bugs.webkit.org/show_bug.cgi?id=229515
-@pytest.mark.skip_browser("webkit")
-async def test_console_should_trigger_correct_log(page: Page, server: Server) -> None:
- await page.goto("about:blank")
- async with page.expect_console_message() as message_info:
- await page.evaluate("async url => fetch(url).catch(e => {})", server.EMPTY_PAGE)
- message = await message_info.value
- assert "Access-Control-Allow-Origin" in message.text
- assert message.type == "error"
-
-
-async def test_console_should_have_location_for_console_api_calls(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- async with page.expect_console_message() as message_info:
- await page.goto(server.PREFIX + "/consolelog.html")
- message = await message_info.value
- assert message.text == "yellow"
- assert message.type == "log"
- location = message.location
- # Engines have different column notion.
- assert location["url"] == server.PREFIX + "/consolelog.html"
- assert location["lineNumber"] == 7
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_console_should_not_throw_when_there_are_console_messages_in_detached_iframes(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- async with page.expect_popup() as page_info:
- await page.evaluate(
- """async() => {
- // 1. Create a popup that Playwright is not connected to.
- const win = window.open('');
- window._popup = win;
- if (window.document.readyState !== 'complete')
- await new Promise(f => window.addEventListener('load', f));
- // 2. In this popup, create an iframe that console.logs a message.
- win.document.body.innerHTML = `
`;
- const frame = win.document.querySelector('iframe');
- if (!frame.contentDocument || frame.contentDocument.readyState !== 'complete')
- await new Promise(f => frame.addEventListener('load', f));
- // 3. After that, remove the iframe.
- frame.remove();
- }"""
- )
- popup = await page_info.value
- # 4. Connect to the popup and make sure it doesn't throw.
- assert await popup.evaluate("1 + 1") == 2
diff --git a/tests/async/test_context_manager.py b/tests/async/test_context_manager.py
deleted file mode 100644
index e1689c4..0000000
--- a/tests/async/test_context_manager.py
+++ /dev/null
@@ -1,36 +0,0 @@
-# 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.
-
-from typing import Dict
-
-import pytest
-
-from playwright.async_api import BrowserContext, BrowserType
-
-
-async def test_context_managers(browser_type: BrowserType, launch_arguments: Dict) -> None:
- async with await browser_type.launch(**launch_arguments) as browser:
- async with await browser.new_context() as context:
- async with await context.new_page():
- assert len(context.pages) == 1
- assert len(context.pages) == 0
- assert len(browser.contexts) == 1
- assert len(browser.contexts) == 0
- assert not browser.is_connected()
-
-
-async def test_context_managers_not_hang(context: BrowserContext) -> None:
- with pytest.raises(Exception, match="Oops!"):
- async with await context.new_page():
- raise Exception("Oops!")
diff --git a/tests/async/test_defaultbrowsercontext.py b/tests/async/test_defaultbrowsercontext.py
deleted file mode 100644
index b489914..0000000
--- a/tests/async/test_defaultbrowsercontext.py
+++ /dev/null
@@ -1,438 +0,0 @@
-# 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 os
-from pathlib import Path
-from typing import (
- Any,
- AsyncGenerator,
- Awaitable,
- Callable,
- Dict,
- Literal,
- Optional,
- Tuple,
-)
-
-import pytest
-from playwright.async_api import BrowserContext, BrowserType, Error, Page, expect
-
-from tests.server import Server
-from tests.utils import must
-
-from .utils import Utils
-
-
-@pytest.fixture()
-async def launch_persistent(
- tmpdir: Path, launch_arguments: Dict, browser_type: BrowserType
-) -> AsyncGenerator[Callable[..., Awaitable[Tuple[Page, BrowserContext]]], None]:
- context: Optional[BrowserContext] = None
-
- async def _launch(**options: Any) -> Tuple[Page, BrowserContext]:
- nonlocal context
- if context:
- raise ValueError("can only launch one persistent context")
- context = await browser_type.launch_persistent_context(
- str(tmpdir), **{**launch_arguments, **options}
- )
- assert context
- return (context.pages[0], context)
-
- yield _launch
- await must(context).close()
-
-
-async def test_context_cookies_should_work(
- server: Server,
- launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]",
- default_same_site_cookie_value: str,
-) -> None:
- (page, context) = await launch_persistent()
- await page.goto(server.EMPTY_PAGE)
- document_cookie = await page.evaluate(
- """() => {
- document.cookie = 'username=John Doe';
- return document.cookie;
- }"""
- )
-
- assert document_cookie == "username=John Doe"
- assert await page.context.cookies() == [
- {
- "name": "username",
- "value": "John Doe",
- "domain": "localhost",
- "path": "/",
- "expires": -1,
- "httpOnly": False,
- "secure": False,
- "sameSite": default_same_site_cookie_value,
- }
- ]
-
-
-async def test_context_add_cookies_should_work(
- server: Server,
- launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]",
- default_same_site_cookie_value: Literal["Lax", "None", "Strict"],
-) -> None:
- (page, context) = await launch_persistent()
- await page.goto(server.EMPTY_PAGE)
- await page.context.add_cookies(
- [
- {
- "url": server.EMPTY_PAGE,
- "name": "username",
- "value": "John Doe",
- "sameSite": default_same_site_cookie_value,
- }
- ]
- )
- assert await page.evaluate("() => document.cookie") == "username=John Doe"
- assert await page.context.cookies() == [
- {
- "name": "username",
- "value": "John Doe",
- "domain": "localhost",
- "path": "/",
- "expires": -1,
- "httpOnly": False,
- "secure": False,
- "sameSite": default_same_site_cookie_value,
- }
- ]
-
-
-async def test_context_clear_cookies_should_work(
- server: Server,
- launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]",
-) -> None:
- (page, context) = await launch_persistent()
- await page.goto(server.EMPTY_PAGE)
- await page.context.add_cookies(
- [
- {"url": server.EMPTY_PAGE, "name": "cookie1", "value": "1"},
- {"url": server.EMPTY_PAGE, "name": "cookie2", "value": "2"},
- ]
- )
- assert await page.evaluate("document.cookie") == "cookie1=1; cookie2=2"
- await page.context.clear_cookies()
- await page.reload()
- assert await page.context.cookies([]) == []
- assert await page.evaluate("document.cookie") == ""
-
-
-async def test_should_not_block_third_party_cookies(
- server: Server,
- launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]",
- is_firefox: bool,
-) -> None:
- (page, context) = await launch_persistent()
- await page.goto(server.EMPTY_PAGE)
- await page.evaluate(
- """src => {
- let fulfill;
- const promise = new Promise(x => fulfill = x);
- const iframe = document.createElement('iframe');
- document.body.appendChild(iframe);
- iframe.onload = fulfill;
- iframe.src = src;
- return promise;
- }""",
- server.CROSS_PROCESS_PREFIX + "/grid.html",
- )
- document_cookie = await page.frames[1].evaluate(
- """() => {
- document.cookie = 'username=John Doe';
- return document.cookie;
- }"""
- )
-
- await page.wait_for_timeout(2000)
- 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")
- 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 == []
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox (WIP)")
-async def test_should_support_viewport_option(
- launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]",
- utils: Utils,
-) -> None:
- (page, context) = await launch_persistent(viewport={"width": 456, "height": 789})
- await utils.verify_viewport(page, 456, 789)
- page2 = await context.new_page()
- await utils.verify_viewport(page2, 456, 789)
-
-
-async def test_should_support_device_scale_factor_option(
- launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]",
-) -> None:
- (page, context) = await launch_persistent(device_scale_factor=3)
- assert await page.evaluate("window.devicePixelRatio") == 3
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_should_support_user_agent_option(
- launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]",
- server: Server,
-) -> None:
- (page, context) = await launch_persistent(user_agent="foobar")
- assert await page.evaluate("() => navigator.userAgent") == "foobar"
- [request, _] = await asyncio.gather(
- server.wait_for_request("/empty.html"),
- page.goto(server.EMPTY_PAGE),
- )
- assert request.getHeader("user-agent") == "foobar"
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_should_support_bypass_csp_option(
- launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]",
- server: Server,
-) -> None:
- (page, context) = await launch_persistent(bypass_csp=True)
- await page.goto(server.PREFIX + "/csp.html")
- await page.add_script_tag(content="window.__injected = 42;")
- assert await page.evaluate("() => window.__injected") == 42
-
-
-async def test_should_support_javascript_enabled_option(
- launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]",
- is_webkit: bool,
-) -> None:
- (page, context) = await launch_persistent(java_script_enabled=False)
- await page.goto('data:text/html, ')
- with pytest.raises(Error) as exc:
- await page.evaluate("something")
- if is_webkit:
- assert "Can't find variable: something" in exc.value.message
- else:
- assert "something is not defined" in exc.value.message
-
-
-async def test_should_support_http_credentials_option(
- server: Server,
- launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]",
-) -> None:
- (page, context) = await launch_persistent(
- http_credentials={"username": "user", "password": "pass"}
- )
- server.set_auth("/playground.html", "user", "pass")
- response = await page.goto(server.PREFIX + "/playground.html")
- assert response
- assert response.status == 200
-
-
-async def test_should_support_offline_option(
- server: Server,
- launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]",
-) -> None:
- (page, context) = await launch_persistent(offline=True)
- with pytest.raises(Error):
- await page.goto(server.EMPTY_PAGE)
-
-
-async def test_should_support_has_touch_option(
- server: Server,
- launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]",
-) -> None:
- (page, context) = await launch_persistent(has_touch=True)
- await page.goto(server.PREFIX + "/mobile.html")
- assert await page.evaluate('() => "ontouchstart" in window')
-
-
-@pytest.mark.skip_browser("firefox")
-async def test_should_work_in_persistent_context(
- server: Server,
- launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]",
-) -> None:
- # Firefox does not support mobile.
- (page, context) = await launch_persistent(
- viewport={"width": 320, "height": 480}, is_mobile=True
- )
- await page.goto(server.PREFIX + "/empty.html")
- assert await page.evaluate("() => window.innerWidth") == 980
-
-
-async def test_should_support_color_scheme_option(
- launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]",
-) -> None:
- (page, context) = await launch_persistent(color_scheme="dark")
- assert await page.evaluate('() => matchMedia("(prefers-color-scheme: light)").matches') is False
- assert await page.evaluate('() => matchMedia("(prefers-color-scheme: dark)").matches')
-
-
-async def test_should_support_timezone_id_option(
- launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]",
-) -> None:
- (page, context) = await launch_persistent(timezone_id="America/Jamaica")
- assert (
- await page.evaluate("() => new Date(1479579154987).toString()")
- == "Sat Nov 19 2016 13:12:34 GMT-0500 (Eastern Standard Time)"
- )
-
-
-async def test_should_support_locale_option(
- launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]",
-) -> None:
- (page, context) = await launch_persistent(locale="fr-FR")
- assert await page.evaluate("() => navigator.language") == "fr-FR"
-
-
-async def test_should_support_geolocation_and_permission_option(
- server: Server,
- launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]",
-) -> None:
- (page, context) = await launch_persistent(
- geolocation={"longitude": 10, "latitude": 10}, permissions=["geolocation"]
- )
- 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}
-
-
-async def test_should_support_ignore_https_errors_option(
- https_server: Server,
- launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]",
-) -> None:
- (page, context) = await launch_persistent(ignore_https_errors=True)
- response = await page.goto(https_server.EMPTY_PAGE)
- assert response
- assert response.ok
-
-
-async def test_should_support_extra_http_headers_option(
- server: Server,
- launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]",
-) -> None:
- (page, context) = await launch_persistent(extra_http_headers={"foo": "bar"})
- [request, _] = await asyncio.gather(
- server.wait_for_request("/empty.html"),
- page.goto(server.EMPTY_PAGE),
- )
- assert request.getHeader("foo") == "bar"
-
-
-async def test_should_accept_user_data_dir(
- tmpdir: Path,
- launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]",
-) -> None:
- (page, context) = await launch_persistent()
- # Note: we need an open page to make sure its functional.
- assert len(os.listdir(tmpdir)) > 0
- await context.close()
- assert len(os.listdir(tmpdir)) > 0
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_should_restore_state_from_userDataDir(
- browser_type: BrowserType,
- launch_arguments: Dict,
- server: Server,
- tmp_path_factory: pytest.TempPathFactory,
-) -> None:
- user_data_dir1 = tmp_path_factory.mktemp("test")
- browser_context = await browser_type.launch_persistent_context(
- user_data_dir1, **launch_arguments
- )
- page = await browser_context.new_page()
- await page.goto(server.EMPTY_PAGE)
- await page.evaluate('() => localStorage.hey = "hello"')
- await browser_context.close()
-
- browser_context2 = await browser_type.launch_persistent_context(
- user_data_dir1, **launch_arguments
- )
- page2 = await browser_context2.new_page()
- await page2.goto(server.EMPTY_PAGE)
- assert await page2.evaluate("() => localStorage.hey") == "hello"
- await browser_context2.close()
-
- user_data_dir2 = tmp_path_factory.mktemp("test")
- browser_context3 = await browser_type.launch_persistent_context(
- user_data_dir2, **launch_arguments
- )
- page3 = await browser_context3.new_page()
- await page3.goto(server.EMPTY_PAGE)
- assert await page3.evaluate("() => localStorage.hey") != "hello"
- await browser_context3.close()
-
-
-async def test_should_have_default_url_when_launching_browser(
- launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]",
-) -> None:
- (page, context) = await launch_persistent()
- urls = list(map(lambda p: p.url, context.pages))
- assert urls == ["about:blank"]
-
-
-@pytest.mark.skip_browser("firefox")
-async def test_should_throw_if_page_argument_is_passed(
- browser_type: BrowserType, server: Server, tmpdir: Path, launch_arguments: Dict
-) -> None:
- options = {**launch_arguments, "args": [server.EMPTY_PAGE]}
- with pytest.raises(Error) as exc:
- await browser_type.launch_persistent_context(tmpdir, **options)
- assert "can not specify page" in exc.value.message
-
-
-async def test_should_fire_close_event_for_a_persistent_context(
- launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]",
-) -> None:
- (page, context) = await launch_persistent()
- fired_event: "asyncio.Future[bool]" = asyncio.Future()
- context.on("close", lambda _: fired_event.set_result(True))
- await context.close()
- await fired_event
-
-
-async def test_should_support_reduced_motion(
- launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]",
-) -> None:
- (page, context) = await launch_persistent(reduced_motion="reduce")
- assert await page.evaluate("matchMedia('(prefers-reduced-motion: reduce)').matches")
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_should_support_har_option(
- assetdir: Path,
- launch_persistent: "Callable[..., asyncio.Future[Tuple[Page, BrowserContext]]]",
-) -> None:
- (page, context) = await launch_persistent()
- await page.route_from_har(har=assetdir / "har-fulfill.har")
- await page.goto("http://no.playwright/")
- assert await page.evaluate("window.value") == "foo"
- await expect(page.locator("body")).to_have_css("background-color", "rgb(255, 0, 0)")
diff --git a/tests/async/test_device_descriptors.py b/tests/async/test_device_descriptors.py
deleted file mode 100644
index f14fc1f..0000000
--- a/tests/async/test_device_descriptors.py
+++ /dev/null
@@ -1,54 +0,0 @@
-# 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.
-from typing import Dict
-
-import pytest
-
-from playwright.async_api import Playwright
-
-
-@pytest.mark.only_browser("chromium")
-async def test_should_work(playwright: Playwright, launch_arguments: Dict) -> None:
- device_descriptor = playwright.devices["Pixel 2"]
- device_type = device_descriptor["default_browser_type"]
- browser = await playwright[device_type].launch(**launch_arguments)
- context = await browser.new_context(
- **device_descriptor,
- )
- page = await context.new_page()
- assert device_descriptor["default_browser_type"] == "chromium"
- assert browser.browser_type.name == "chromium"
-
- assert "Pixel 2" in device_descriptor["user_agent"]
- assert "Pixel 2" in await page.evaluate("navigator.userAgent")
-
- assert device_descriptor["device_scale_factor"] > 2
- assert await page.evaluate("window.devicePixelRatio") > 2
-
- assert device_descriptor["viewport"]["height"] > 700
- assert device_descriptor["viewport"]["height"] < 800
- inner_height = await page.evaluate("window.screen.availHeight")
- assert inner_height > 700
- assert inner_height < 800
-
- assert device_descriptor["viewport"]["width"] > 400
- assert device_descriptor["viewport"]["width"] < 500
- inner_width = await page.evaluate("window.screen.availWidth")
- assert inner_width > 400
- assert inner_width < 500
-
- assert device_descriptor["has_touch"]
- assert device_descriptor["is_mobile"]
-
- await browser.close()
diff --git a/tests/async/test_dialog.py b/tests/async/test_dialog.py
deleted file mode 100644
index d33b974..0000000
--- a/tests/async/test_dialog.py
+++ /dev/null
@@ -1,102 +0,0 @@
-# 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.
-
-from playwright.async_api import Browser, Dialog, Page
-
-
-async def test_should_fire(page: Page) -> None:
- result = []
-
- async def on_dialog(dialog: Dialog) -> None:
- result.append(True)
- assert dialog.type == "alert"
- assert dialog.default_value == ""
- assert dialog.message == "yo"
- await dialog.accept()
-
- page.on("dialog", on_dialog)
- await page.evaluate("alert('yo')")
- assert result
-
-
-async def test_should_allow_accepting_prompts(page: Page) -> None:
- result = []
-
- async def on_dialog(dialog: Dialog) -> None:
- result.append(True)
- assert dialog.type == "prompt"
- assert dialog.default_value == "yes."
- assert dialog.message == "question?"
- await dialog.accept("answer!")
-
- page.on("dialog", on_dialog)
- assert await page.evaluate("prompt('question?', 'yes.')") == "answer!"
- assert result
-
-
-async def test_should_dismiss_the_prompt(page: Page) -> None:
- result = []
-
- async def on_dialog(dialog: Dialog) -> None:
- result.append(True)
- await dialog.dismiss()
-
- page.on("dialog", on_dialog)
- assert await page.evaluate("prompt('question?')") is None
- assert result
-
-
-async def test_should_accept_the_confirm_prompt(page: Page) -> None:
- result = []
-
- async def on_dialog(dialog: Dialog) -> None:
- result.append(True)
- await dialog.accept()
-
- page.on("dialog", on_dialog)
- assert await page.evaluate("confirm('boolean?')") is True
- assert result
-
-
-async def test_should_dismiss_the_confirm_prompt(page: Page) -> None:
- result = []
-
- async def on_dialog(dialog: Dialog) -> None:
- result.append(True)
- await dialog.dismiss()
-
- page.on("dialog", on_dialog)
- assert await page.evaluate("confirm('boolean?')") is False
- assert result
-
-
-async def test_should_be_able_to_close_context_with_open_alert(
- browser: Browser,
-) -> None:
- context = await browser.new_context()
- page = await context.new_page()
- async with page.expect_event("dialog"):
- await page.evaluate("() => setTimeout(() => alert('hello'), 0)", None)
- await context.close()
-
-
-async def test_should_auto_dismiss_the_prompt_without_listeners(page: Page) -> None:
- result = await page.evaluate('() => prompt("question?")')
- assert not result
-
-
-async def test_should_auto_dismiss_the_alert_without_listeners(page: Page) -> None:
- await page.set_content('
Click me
')
- await page.click("div")
- assert await page.evaluate('"window._clicked"')
diff --git a/tests/async/test_dispatch_event.py.disabled b/tests/async/test_dispatch_event.py.disabled
deleted file mode 100644
index 50b02ba..0000000
--- a/tests/async/test_dispatch_event.py.disabled
+++ /dev/null
@@ -1,191 +0,0 @@
-# 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.
-
-
-from playwright.async_api import Page, Selectors
-from tests.server import Server
-
-from .utils import Utils
-
-
-async def test_should_dispatch_click_event(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/button.html")
- await page.dispatch_event("button", "click")
- assert await page.evaluate("() => result") == "Clicked"
-
-
-async def test_should_dispatch_click_event_properties(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/input/button.html")
- await page.dispatch_event("button", "click")
- assert await page.evaluate("() => bubbles")
- assert await page.evaluate("() => cancelable")
- assert await page.evaluate("() => composed")
-
-
-async def test_should_dispatch_click_svg(page: Page) -> None:
- await page.set_content(
- """
-
-
-
- """
- )
- await page.dispatch_event("circle", "click")
- assert await page.evaluate("() => window.__CLICKED") == 42
-
-
-async def test_should_dispatch_click_on_a_span_with_an_inline_element_inside(
- page: Page,
-) -> None:
- await page.set_content(
- """
-
-
- """
- )
- await page.dispatch_event("span", "click")
- assert await page.evaluate("() => window.CLICKED") == 42
-
-
-async def test_should_dispatch_click_after_navigation(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/input/button.html")
- await page.dispatch_event("button", "click")
- await page.goto(server.PREFIX + "/input/button.html")
- await page.dispatch_event("button", "click")
- assert await page.evaluate("() => result") == "Clicked"
-
-
-async def test_should_dispatch_click_after_a_cross_origin_navigation(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/input/button.html")
- await page.dispatch_event("button", "click")
- await page.goto(server.CROSS_PROCESS_PREFIX + "/input/button.html")
- await page.dispatch_event("button", "click")
- assert await page.evaluate("() => result") == "Clicked"
-
-
-async def test_should_not_fail_when_element_is_blocked_on_hover(page: Page) -> None:
- await page.set_content(
- """
-
- Click me
-
- """
- )
- await page.dispatch_event("button", "click")
- assert await page.evaluate("() => window.clicked")
-
-
-async def test_should_dispatch_click_when_node_is_added_in_shadow_dom(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- watchdog = page.dispatch_event("span", "click")
- await page.evaluate(
- """() => {
- const div = document.createElement('div');
- div.attachShadow({mode: 'open'});
- document.body.appendChild(div);
- }"""
- )
- await page.evaluate("() => new Promise(f => setTimeout(f, 100))")
- await page.evaluate(
- """() => {
- const span = document.createElement('span');
- span.textContent = 'Hello from shadow';
- span.addEventListener('click', () => window.clicked = true);
- document.querySelector('div').shadowRoot.appendChild(span);
- }"""
- )
- await watchdog
- assert await page.evaluate("() => window.clicked")
-
-
-async def test_should_be_atomic(selectors: Selectors, page: Page, utils: Utils) -> None:
- await utils.register_selector_engine(
- selectors,
- "dispatch_event",
- """{
- create(root, target) { },
- query(root, selector) {
- const result = root.querySelector(selector);
- if (result)
- Promise.resolve().then(() => result.onclick = "");
- return result;
- },
- queryAll(root, selector) {
- const result = Array.from(root.querySelectorAll(selector));
- for (const e of result)
- Promise.resolve().then(() => result.onclick = "");
- return result;
- }
- }""",
- )
- await page.set_content('
Hello
')
- await page.dispatch_event("dispatch_event=div", "click")
- assert await page.evaluate("() => window._clicked")
-
-
-async def test_should_dispatch_drag_drop_events(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/drag-n-drop.html")
- dataTransfer = await page.evaluate_handle("() => new DataTransfer()")
- await page.dispatch_event("#source", "dragstart", {"dataTransfer": dataTransfer})
- await page.dispatch_event("#target", "drop", {"dataTransfer": dataTransfer})
- assert await page.evaluate(
- """() => {
- return source.parentElement === target;
- }"""
- )
-
-
-async def test_should_dispatch_drag_and_drop_events_element_handle(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/drag-n-drop.html")
- dataTransfer = await page.evaluate_handle("() => new DataTransfer()")
- source = await page.query_selector("#source")
- assert source
- await source.dispatch_event("dragstart", {"dataTransfer": dataTransfer})
- target = await page.query_selector("#target")
- assert target
- await target.dispatch_event("drop", {"dataTransfer": dataTransfer})
- assert await page.evaluate(
- """() => {
- return source.parentElement === target;
- }"""
- )
-
-
-async def test_should_dispatch_click_event_element_handle(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/input/button.html")
- button = await page.query_selector("button")
- assert button
- await button.dispatch_event("click")
- assert await page.evaluate("() => result") == "Clicked"
diff --git a/tests/async/test_download.py b/tests/async/test_download.py
deleted file mode 100644
index 04d0f2e..0000000
--- a/tests/async/test_download.py
+++ /dev/null
@@ -1,376 +0,0 @@
-# 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 os
-from asyncio.futures import Future
-from pathlib import Path
-from typing import Callable, Generator
-
-import pytest
-
-from playwright.async_api import Browser, Download, Error, Page
-from tests.server import Server, TestServerRequest
-from tests.utils import TARGET_CLOSED_ERROR_MESSAGE
-
-
-def assert_file_content(path: Path, content: str) -> None:
- with open(path, "r") as fd:
- assert fd.read() == content
-
-
-@pytest.fixture(autouse=True)
-def after_each_hook(server: Server) -> Generator[None, None, None]:
- def handle_download(request: TestServerRequest) -> None:
- request.setHeader("Content-Type", "application/octet-stream")
- request.setHeader("Content-Disposition", "attachment")
- request.write(b"Hello world")
- request.finish()
-
- def handle_download_with_file_name(request: TestServerRequest) -> None:
- request.setHeader("Content-Type", "application/octet-stream")
- request.setHeader("Content-Disposition", "attachment; filename=file.txt")
- request.write(b"Hello world")
- request.finish()
-
- server.set_route("/download", handle_download)
- server.set_route("/downloadWithFilename", handle_download_with_file_name)
- yield
-
-
-async def test_should_report_downloads_with_accept_downloads_false(
- page: Page, server: Server
-) -> None:
- await page.set_content(f'
download ')
- async with page.expect_download() as download_info:
- await page.click("a")
- download = await download_info.value
- assert download.page is page
- assert download.url == f"{server.PREFIX}/downloadWithFilename"
- assert download.suggested_filename == "file.txt"
- assert (
- repr(download)
- == f"
"
- )
- assert await download.path()
- assert await download.failure() is None
-
-
-async def test_should_report_downloads_with_accept_downloads_true(
- browser: Browser, server: Server
-) -> None:
- page = await browser.new_page(accept_downloads=True)
- await page.set_content(f'download ')
- async with page.expect_download() as download_info:
- await page.click("a")
- download = await download_info.value
- path = await download.path()
- assert os.path.isfile(path)
- assert_file_content(path, "Hello world")
- await page.close()
-
-
-async def test_should_save_to_user_specified_path(
- tmpdir: Path, browser: Browser, server: Server
-) -> None:
- page = await browser.new_page(accept_downloads=True)
- await page.set_content(f'download ')
- async with page.expect_download() as download_info:
- await page.click("a")
- download = await download_info.value
- user_path = tmpdir / "download.txt"
- await download.save_as(user_path)
- assert user_path.exists()
- assert user_path.read_text("utf-8") == "Hello world"
- await page.close()
-
-
-async def test_should_save_to_user_specified_path_without_updating_original_path(
- tmpdir: Path, browser: Browser, server: Server
-) -> None:
- page = await browser.new_page(accept_downloads=True)
- await page.set_content(f'download ')
- async with page.expect_download() as download_info:
- await page.click("a")
- download = await download_info.value
- user_path = tmpdir / "download.txt"
- await download.save_as(user_path)
- assert user_path.exists()
- assert user_path.read_text("utf-8") == "Hello world"
-
- originalPath = Path(await download.path())
- assert originalPath.exists()
- assert originalPath.read_text("utf-8") == "Hello world"
- await page.close()
-
-
-async def test_should_save_to_two_different_paths_with_multiple_save_as_calls(
- tmpdir: Path, browser: Browser, server: Server
-) -> None:
- page = await browser.new_page(accept_downloads=True)
- await page.set_content(f'download ')
- async with page.expect_download() as download_info:
- await page.click("a")
- download = await download_info.value
- user_path = tmpdir / "download.txt"
- await download.save_as(user_path)
- assert user_path.exists()
- assert user_path.read_text("utf-8") == "Hello world"
-
- anotheruser_path = tmpdir / "download (2).txt"
- await download.save_as(anotheruser_path)
- assert anotheruser_path.exists()
- assert anotheruser_path.read_text("utf-8") == "Hello world"
- await page.close()
-
-
-async def test_should_save_to_overwritten_filepath(
- tmpdir: Path, browser: Browser, server: Server
-) -> None:
- page = await browser.new_page(accept_downloads=True)
- await page.set_content(f'download ')
- async with page.expect_download() as download_info:
- await page.click("a")
- download = await download_info.value
- user_path = tmpdir / "download.txt"
- await download.save_as(user_path)
- assert len(list(Path(tmpdir).glob("*.*"))) == 1
- await download.save_as(user_path)
- assert len(list(Path(tmpdir).glob("*.*"))) == 1
- assert user_path.exists()
- assert user_path.read_text("utf-8") == "Hello world"
- await page.close()
-
-
-async def test_should_create_subdirectories_when_saving_to_non_existent_user_specified_path(
- tmpdir: Path, browser: Browser, server: Server
-) -> None:
- page = await browser.new_page(accept_downloads=True)
- await page.set_content(f'download ')
- async with page.expect_download() as download_info:
- await page.click("a")
- download = await download_info.value
- nested_path = tmpdir / "these" / "are" / "directories" / "download.txt"
- await download.save_as(nested_path)
- assert nested_path.exists()
- assert nested_path.read_text("utf-8") == "Hello world"
- await page.close()
-
-
-async def test_should_error_when_saving_with_downloads_disabled(
- tmpdir: Path, browser: Browser, server: Server
-) -> None:
- page = await browser.new_page(accept_downloads=False)
- await page.set_content(f'download ')
- async with page.expect_download() as download_info:
- await page.click("a")
- download = await download_info.value
- user_path = tmpdir / "download.txt"
- with pytest.raises(Error) as exc:
- await download.save_as(user_path)
- assert (
- "Pass 'accept_downloads=True' when you are creating your browser context"
- in exc.value.message
- )
- assert (
- "Pass 'accept_downloads=True' when you are creating your browser context."
- == await download.failure()
- )
- await page.close()
-
-
-async def test_should_error_when_saving_after_deletion(
- tmpdir: Path, browser: Browser, server: Server
-) -> None:
- page = await browser.new_page(accept_downloads=True)
- await page.set_content(f'download ')
- async with page.expect_download() as download_info:
- await page.click("a")
- download = await download_info.value
- user_path = tmpdir / "download.txt"
- await download.delete()
- with pytest.raises(Error) as exc:
- await download.save_as(user_path)
- assert TARGET_CLOSED_ERROR_MESSAGE in exc.value.message
- await page.close()
-
-
-async def test_should_report_non_navigation_downloads(browser: Browser, server: Server) -> None:
- # Mac WebKit embedder does not download in this case, although Safari does.
- def handle_download(request: TestServerRequest) -> None:
- request.setHeader("Content-Type", "application/octet-stream")
- request.write(b"Hello world")
- request.finish()
-
- server.set_route("/download", handle_download)
-
- page = await browser.new_page(accept_downloads=True)
- await page.goto(server.EMPTY_PAGE)
- await page.set_content(f'download ')
- async with page.expect_download() as download_info:
- await page.click("a")
- download = await download_info.value
- assert download.suggested_filename == "file.txt"
- path = await download.path()
- assert os.path.exists(path)
- assert_file_content(path, "Hello world")
- await page.close()
-
-
-async def test_report_download_path_within_page_on_download_handler_for_files(
- browser: Browser, server: Server
-) -> None:
- page = await browser.new_page(accept_downloads=True)
- on_download_path: Future[Path] = asyncio.Future()
-
- async def on_download(download: Download) -> None:
- on_download_path.set_result(await download.path())
-
- page.once(
- "download",
- lambda res: asyncio.create_task(on_download(res)),
- )
- await page.set_content(f'download ')
- await page.click("a")
- path = await on_download_path
- assert_file_content(path, "Hello world")
- await page.close()
-
-
-async def test_download_report_download_path_within_page_on_handle_for_blobs(
- browser: Browser, server: Server
-) -> None:
- page = await browser.new_page(accept_downloads=True)
- on_download_path: "asyncio.Future[Path]" = asyncio.Future()
-
- async def on_download(download: Download) -> None:
- on_download_path.set_result(await download.path())
-
- page.once(
- "download",
- lambda res: asyncio.create_task(on_download(res)),
- )
-
- await page.goto(server.PREFIX + "/download-blob.html")
- await page.click("a")
- path = await on_download_path
- assert_file_content(path, "Hello world")
- await page.close()
-
-
-@pytest.mark.only_browser("chromium")
-async def test_should_report_alt_click_downloads(browser: Browser, server: Server) -> None:
- # Firefox does not download on alt-click by default.
- # Our WebKit embedder does not download on alt-click, although Safari does.
- def handle_download(request: TestServerRequest) -> None:
- request.setHeader("Content-Type", "application/octet-stream")
- request.write(b"Hello world")
- request.finish()
-
- server.set_route("/download", handle_download)
-
- page = await browser.new_page(accept_downloads=True)
- await page.goto(server.EMPTY_PAGE)
- await page.set_content(f'download ')
- async with page.expect_download() as download_info:
- await page.click("a", modifiers=["Alt"])
- download = await download_info.value
- path = await download.path()
- assert os.path.exists(path)
- assert_file_content(path, "Hello world")
- await page.close()
-
-
-async def test_should_report_new_window_downloads(browser: Browser, server: Server) -> None:
- page = await browser.new_page(accept_downloads=True)
- await page.set_content(f'download ')
- async with page.expect_download() as download_info:
- await page.click("a")
- download = await download_info.value
- path = await download.path()
- assert os.path.exists(path)
- await page.close()
-
-
-async def test_should_delete_file(browser: Browser, server: Server) -> None:
- page = await browser.new_page(accept_downloads=True)
- await page.set_content(f'download ')
- async with page.expect_download() as download_info:
- await page.click("a")
- download = await download_info.value
- path = await download.path()
- assert os.path.exists(path)
- await download.delete()
- assert os.path.exists(path) is False
- await page.close()
-
-
-async def test_should_delete_downloads_on_context_destruction(
- browser: Browser, server: Server
-) -> None:
- page = await browser.new_page(accept_downloads=True)
- await page.set_content(f'download ')
- async with page.expect_download() as download_info:
- await page.click("a")
- download1 = await download_info.value
- async with page.expect_download() as download_info:
- await page.click("a")
- download2 = await download_info.value
- path1 = await download1.path()
- path2 = await download2.path()
- assert os.path.exists(path1)
- assert os.path.exists(path2)
- await page.context.close()
- assert os.path.exists(path1) is False
- assert os.path.exists(path2) is False
-
-
-async def test_should_delete_downloads_on_browser_gone(
- browser_factory: "Callable[..., asyncio.Future[Browser]]", server: Server
-) -> None:
- browser = await browser_factory()
- page = await browser.new_page(accept_downloads=True)
- await page.set_content(f'download ')
- async with page.expect_download() as download_info:
- await page.click("a")
- download1 = await download_info.value
- async with page.expect_download() as download_info:
- await page.click("a")
- download2 = await download_info.value
- path1 = await download1.path()
- path2 = await download2.path()
- assert os.path.exists(path1)
- assert os.path.exists(path2)
- await browser.close()
- assert os.path.exists(path1) is False
- assert os.path.exists(path2) is False
- assert os.path.exists(os.path.join(path1, "..")) is False
-
-
-async def test_download_cancel_should_work(browser: Browser, server: Server) -> None:
- def handle_download(request: TestServerRequest) -> None:
- request.setHeader("Content-Type", "application/octet-stream")
- request.setHeader("Content-Disposition", "attachment")
- # Chromium requires a large enough payload to trigger the download event soon enough
- request.write(b"a" * 4096)
- request.write(b"foo")
-
- server.set_route("/downloadWithDelay", handle_download)
- page = await browser.new_page(accept_downloads=True)
- await page.set_content(f'download ')
- async with page.expect_download() as download_info:
- await page.click("a")
- download = await download_info.value
- await download.cancel()
- assert await download.failure() == "canceled"
- await page.close()
diff --git a/tests/async/test_element_handle.py.disabled b/tests/async/test_element_handle.py.disabled
deleted file mode 100644
index ce46f04..0000000
--- a/tests/async/test_element_handle.py.disabled
+++ /dev/null
@@ -1,754 +0,0 @@
-# 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
-from typing import Optional, cast
-
-import pytest
-from playwright.async_api import Browser, ElementHandle, Error, FloatRect, Page
-
-from tests.server import Server
-
-from .utils import Utils
-
-
-async def test_bounding_box(page: Page, server: Server) -> None:
- await page.set_viewport_size({"width": 500, "height": 500})
- await page.goto(server.PREFIX + "/grid.html")
- element_handle = await page.query_selector(".box:nth-of-type(13)")
- assert element_handle
- box = await element_handle.bounding_box()
- assert box == {"x": 100, "y": 50, "width": 50, "height": 50}
-
-
-async def test_bounding_box_handle_nested_frames(page: Page, server: Server) -> None:
- await page.set_viewport_size({"width": 500, "height": 500})
- await page.goto(server.PREFIX + "/frames/nested-frames.html")
- nested_frame = page.frame(name="dos")
- assert nested_frame
- element_handle = await nested_frame.query_selector("div")
- assert element_handle
- box = await element_handle.bounding_box()
- assert box == {"x": 24, "y": 224, "width": 268, "height": 18}
-
-
-async def test_bounding_box_return_null_for_invisible_elements(page: Page, server: Server) -> None:
- await page.set_content('hi
')
- element = await page.query_selector("div")
- assert element
- assert await element.bounding_box() is None
-
-
-async def test_bounding_box_force_a_layout(page: Page, server: Server) -> None:
- await page.set_viewport_size({"width": 500, "height": 500})
- await page.set_content('hello
')
- element_handle = await page.query_selector("div")
- assert element_handle
- await page.evaluate('element => element.style.height = "200px"', element_handle)
- box = await element_handle.bounding_box()
- assert box == {"x": 8, "y": 8, "width": 100, "height": 200}
-
-
-async def test_bounding_box_with_SVG_nodes(page: Page, server: Server) -> None:
- await page.set_content(
- """
-
- """
- )
- element = await page.query_selector("#therect")
- assert element
- pw_bounding_box = await element.bounding_box()
- web_bounding_box = await page.evaluate(
- """e => {
- rect = e.getBoundingClientRect()
- return {x: rect.x, y: rect.y, width: rect.width, height: rect.height}
- }""",
- element,
- )
- assert pw_bounding_box == web_bounding_box
-
-
-@pytest.mark.skip_browser("firefox")
-async def test_bounding_box_with_page_scale(browser: Browser, server: Server) -> None:
- context = await browser.new_context(viewport={"width": 400, "height": 400}, is_mobile=True)
- page = await context.new_page()
- await page.goto(server.PREFIX + "/input/button.html")
- button = await page.query_selector("button")
- assert button
- await button.evaluate(
- """button => {
- document.body.style.margin = '0'
- button.style.borderWidth = '0'
- button.style.width = '200px'
- button.style.height = '20px'
- button.style.marginLeft = '17px'
- button.style.marginTop = '23px'
- }"""
- )
-
- box = await button.bounding_box()
- assert box
- assert round(box["x"] * 100) == 17 * 100
- assert round(box["y"] * 100) == 23 * 100
- assert round(box["width"] * 100) == 200 * 100
- assert round(box["height"] * 100) == 20 * 100
- await context.close()
-
-
-async def test_bounding_box_when_inline_box_child_is_outside_of_viewport(
- page: Page,
-) -> None:
- await page.set_content(
- """
-
- woof doggo
- """
- )
- handle = await page.query_selector("span")
- assert handle
- box = await handle.bounding_box()
- web_bounding_box = await handle.evaluate(
- """e => {
- rect = e.getBoundingClientRect();
- return {x: rect.x, y: rect.y, width: rect.width, height: rect.height};
- }"""
- )
-
- def roundbox(b: Optional[FloatRect]) -> FloatRect:
- assert b
- return {
- "x": round(b["x"] * 100),
- "y": round(b["y"] * 100),
- "width": round(b["width"] * 100),
- "height": round(b["height"] * 100),
- }
-
- assert roundbox(box) == roundbox(web_bounding_box)
-
-
-async def test_content_frame(page: Page, server: Server, utils: Utils) -> None:
- await page.goto(server.EMPTY_PAGE)
- await utils.attach_frame(page, "frame1", server.EMPTY_PAGE)
- element_handle = await page.query_selector("#frame1")
- assert element_handle
- frame = await element_handle.content_frame()
- assert frame == page.frames[1]
-
-
-async def test_content_frame_for_non_iframes(page: Page, server: Server, utils: Utils) -> None:
- await page.goto(server.EMPTY_PAGE)
- await utils.attach_frame(page, "frame1", server.EMPTY_PAGE)
- frame = page.frames[1]
- element_handle = cast(ElementHandle, await frame.evaluate_handle("document.body"))
- assert await element_handle.content_frame() is None
-
-
-async def test_content_frame_for_document_element(page: Page, server: Server, utils: Utils) -> None:
- await page.goto(server.EMPTY_PAGE)
- await utils.attach_frame(page, "frame1", server.EMPTY_PAGE)
- frame = page.frames[1]
- element_handle = cast(ElementHandle, await frame.evaluate_handle("document.documentElement"))
- assert await element_handle.content_frame() is None
-
-
-async def test_owner_frame(page: Page, server: Server, utils: Utils) -> None:
- await page.goto(server.EMPTY_PAGE)
- await utils.attach_frame(page, "frame1", server.EMPTY_PAGE)
- frame = page.frames[1]
- element_handle = cast(ElementHandle, await frame.evaluate_handle("document.body"))
- assert await element_handle.owner_frame() == frame
-
-
-async def test_owner_frame_for_cross_process_iframes(
- page: Page, server: Server, utils: Utils
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- await utils.attach_frame(page, "frame1", server.CROSS_PROCESS_PREFIX + "/empty.html")
- frame = page.frames[1]
- element_handle = cast(ElementHandle, await frame.evaluate_handle("document.body"))
- assert await element_handle.owner_frame() == frame
-
-
-async def test_owner_frame_for_document(page: Page, server: Server, utils: Utils) -> None:
- await page.goto(server.EMPTY_PAGE)
- await utils.attach_frame(page, "frame1", server.EMPTY_PAGE)
- frame = page.frames[1]
- element_handle = cast(ElementHandle, await frame.evaluate_handle("document"))
- assert await element_handle.owner_frame() == frame
-
-
-async def test_owner_frame_for_iframe_elements(page: Page, server: Server, utils: Utils) -> None:
- await page.goto(server.EMPTY_PAGE)
- await utils.attach_frame(page, "frame1", server.EMPTY_PAGE)
- frame = page.main_frame
- element_handle = cast(
- ElementHandle, await frame.evaluate_handle('document.querySelector("#frame1")')
- )
- assert await element_handle.owner_frame() == frame
-
-
-async def test_owner_frame_for_cross_frame_evaluations(
- page: Page, server: Server, utils: Utils
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- await utils.attach_frame(page, "frame1", server.EMPTY_PAGE)
- frame = page.main_frame
- element_handle = cast(
- ElementHandle,
- await frame.evaluate_handle(
- 'document.querySelector("#frame1").contentWindow.document.body'
- ),
- )
- assert await element_handle.owner_frame() == frame.child_frames[0]
-
-
-async def test_owner_frame_for_detached_elements(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- div_handle = cast(
- ElementHandle,
- await page.evaluate_handle(
- """() => {
- div = document.createElement('div');
- document.body.appendChild(div);
- return div;
- }"""
- ),
- )
- assert div_handle
-
- assert await div_handle.owner_frame() == page.main_frame
- await page.evaluate(
- """() => {
- div = document.querySelector('div')
- document.body.removeChild(div)
- }"""
- )
- assert await div_handle.owner_frame() == page.main_frame
-
-
-async def test_owner_frame_for_adopted_elements(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- async with page.expect_popup() as popup_info:
- await page.evaluate("url => window.__popup = window.open(url)", server.EMPTY_PAGE)
- popup = await popup_info.value
- div_handle = cast(
- ElementHandle,
- await page.evaluate_handle(
- """() => {
- div = document.createElement('div');
- document.body.appendChild(div);
- return div;
- }"""
- ),
- )
- assert div_handle
- assert await div_handle.owner_frame() == page.main_frame
- await popup.wait_for_load_state("domcontentloaded")
- await page.evaluate(
- """() => {
- div = document.querySelector('div');
- window.__popup.document.body.appendChild(div);
- }"""
- )
- assert await div_handle.owner_frame() == popup.main_frame
-
-
-async def test_click(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/button.html")
- button = await page.query_selector("button")
- assert button
- await button.click()
- assert await page.evaluate("result") == "Clicked"
-
-
-async def test_click_with_node_removed(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/button.html")
- await page.evaluate('delete window["Node"]')
- button = await page.query_selector("button")
- assert button
- await button.click()
- assert await page.evaluate("result") == "Clicked"
-
-
-async def test_click_for_shadow_dom_v1(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/shadow.html")
- button_handle = cast(ElementHandle, await page.evaluate_handle("button"))
- await button_handle.click()
- assert await page.evaluate("clicked")
-
-
-async def test_click_for_TextNodes(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/button.html")
- buttonTextNode = cast(
- ElementHandle,
- await page.evaluate_handle('document.querySelector("button").firstChild'),
- )
- await buttonTextNode.click()
- assert await page.evaluate("result") == "Clicked"
-
-
-async def test_click_throw_for_detached_nodes(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/button.html")
- button = await page.query_selector("button")
- assert button
- await page.evaluate("button => button.remove()", button)
- with pytest.raises(Error) as exc_info:
- await button.click()
- assert "Element is not attached to the DOM" in exc_info.value.message
-
-
-async def test_click_throw_for_hidden_nodes_with_force(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/button.html")
- button = await page.query_selector("button")
- assert button
- await page.evaluate('button => button.style.display = "none"', button)
- with pytest.raises(Error) as exc_info:
- await button.click(force=True)
- assert "Element is not visible" in exc_info.value.message
-
-
-async def test_click_throw_for_recursively_hidden_nodes_with_force(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/input/button.html")
- button = await page.query_selector("button")
- assert button
- await page.evaluate('button => button.parentElement.style.display = "none"', button)
- with pytest.raises(Error) as exc_info:
- await button.click(force=True)
- assert "Element is not visible" in exc_info.value.message
-
-
-async def test_click_throw_for__br__elements_with_force(page: Page, server: Server) -> None:
- await page.set_content("hello goodbye")
- br = await page.query_selector("br")
- assert br
- with pytest.raises(Error) as exc_info:
- await br.click(force=True)
- assert "Element is outside of the viewport" in exc_info.value.message
-
-
-async def test_double_click_the_button(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/button.html")
- await page.evaluate(
- """() => {
- window.double = false;
- button = document.querySelector('button');
- button.addEventListener('dblclick', event => {
- window.double = true;
- });
- }"""
- )
- button = await page.query_selector("button")
- assert button
- await button.dblclick()
- assert await page.evaluate("double")
- assert await page.evaluate("result") == "Clicked"
-
-
-async def test_hover(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/scrollable.html")
- button = await page.query_selector("#button-6")
- assert button
- await button.hover()
- assert await page.evaluate('document.querySelector("button:hover").id') == "button-6"
-
-
-async def test_hover_when_node_is_removed(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/scrollable.html")
- await page.evaluate('delete window["Node"]')
- button = await page.query_selector("#button-6")
- assert button
- await button.hover()
- assert await page.evaluate('document.querySelector("button:hover").id') == "button-6"
-
-
-async def test_scroll(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/offscreenbuttons.html")
- for i in range(11):
- button = await page.query_selector(f"#btn{i}")
- assert button
- before = await button.evaluate(
- """button => {
- return button.getBoundingClientRect().right - window.innerWidth
- }"""
- )
-
- assert before == 10 * i
- await button.scroll_into_view_if_needed()
- after = await button.evaluate(
- """button => {
- return button.getBoundingClientRect().right - window.innerWidth
- }"""
- )
-
- assert after <= 0
- await page.evaluate("() => window.scrollTo(0, 0)")
-
-
-async def test_scroll_should_throw_for_detached_element(page: Page, server: Server) -> None:
- await page.set_content("Hello
")
- div = await page.query_selector("div")
- assert div
- await div.evaluate("div => div.remove()")
- with pytest.raises(Error) as exc_info:
- await div.scroll_into_view_if_needed()
- assert "Element is not attached to the DOM" in exc_info.value.message
-
-
-async def waiting_helper(page: Page, after: str) -> None:
- div = await page.query_selector("div")
- assert div
- done = []
-
- async def scroll() -> None:
- done.append(False)
- await div.scroll_into_view_if_needed()
- done.append(True)
-
- promise = asyncio.create_task(scroll())
- await asyncio.sleep(0) # execute scheduled tasks, but don't await them
- await page.evaluate("() => new Promise(f => setTimeout(f, 1000))")
- assert done == [False]
- await div.evaluate(after)
- await promise
- assert done == [False, True]
-
-
-async def test_should_wait_for_display_none_to_become_visible(page: Page) -> None:
- await page.set_content('Hello
')
- await waiting_helper(page, 'div => div.style.display = "block"')
-
-
-async def test_should_work_for_visibility_hidden_element(page: Page) -> None:
- await page.set_content('Hello
')
- div = await page.query_selector("div")
- assert div
- await div.scroll_into_view_if_needed()
-
-
-async def test_should_work_for_zero_sized_element(page: Page) -> None:
- await page.set_content('Hello
')
- div = await page.query_selector("div")
- assert div
- await div.scroll_into_view_if_needed()
-
-
-async def test_should_wait_for_nested_display_none_to_become_visible(
- page: Page,
-) -> None:
- await page.set_content('Hello
')
- await waiting_helper(page, 'div => div.parentElement.style.display = "block"')
-
-
-async def test_should_timeout_waiting_for_visible(page: Page) -> None:
- await page.set_content('Hello
')
- div = await page.query_selector("div")
- assert div
- with pytest.raises(Error) as exc_info:
- await div.scroll_into_view_if_needed(timeout=3000)
- assert "element is not visible" in exc_info.value.message
- assert "retrying scroll into view action" in exc_info.value.message
-
-
-async def test_fill_input(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/textarea.html")
- handle = await page.query_selector("input")
- assert handle
- await handle.fill("some value")
- assert await page.evaluate("result") == "some value"
-
-
-async def test_fill_input_when_Node_is_removed(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/textarea.html")
- await page.evaluate('delete window["Node"]')
- handle = await page.query_selector("input")
- assert handle
- await handle.fill("some value")
- assert await page.evaluate("result") == "some value"
-
-
-async def test_select_textarea(
- page: Page, server: Server, is_firefox: bool, is_webkit: bool
-) -> None:
- await page.goto(server.PREFIX + "/input/textarea.html")
- textarea = await page.query_selector("textarea")
- assert textarea
- await textarea.evaluate('textarea => textarea.value = "some value"')
- await textarea.select_text()
- if is_firefox or is_webkit:
- assert await textarea.evaluate("el => el.selectionStart") == 0
- assert await textarea.evaluate("el => el.selectionEnd") == 10
- else:
- assert await page.evaluate("() => window.getSelection().toString()") == "some value"
-
-
-async def test_select_input(page: Page, server: Server, is_firefox: bool, is_webkit: bool) -> None:
- await page.goto(server.PREFIX + "/input/textarea.html")
- input = await page.query_selector("input")
- assert input
- await input.evaluate('input => input.value = "some value"')
- await input.select_text()
- if is_firefox or is_webkit:
- assert await input.evaluate("el => el.selectionStart") == 0
- assert await input.evaluate("el => el.selectionEnd") == 10
- else:
- assert await page.evaluate("() => window.getSelection().toString()") == "some value"
-
-
-async def test_select_text_select_plain_div(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/textarea.html")
- div = await page.query_selector("div.plain")
- assert div
- await div.select_text()
- assert await page.evaluate("() => window.getSelection().toString()") == "Plain div"
-
-
-async def test_select_text_timeout_waiting_for_invisible_element(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/input/textarea.html")
- textarea = await page.query_selector("textarea")
- assert textarea
- await textarea.evaluate('e => e.style.display = "none"')
- with pytest.raises(Error) as exc_info:
- await textarea.select_text(timeout=3000)
- assert "element is not visible" in exc_info.value.message
-
-
-async def test_select_text_wait_for_visible(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/textarea.html")
- textarea = await page.query_selector("textarea")
- assert textarea
- await textarea.evaluate('textarea => textarea.value = "some value"')
- await textarea.evaluate('e => e.style.display = "none"')
- done = []
-
- async def select_text() -> None:
- done.append(False)
- await textarea.select_text(timeout=3000)
- done.append(True)
-
- promise = asyncio.create_task(select_text())
- await asyncio.sleep(0) # execute scheduled tasks, but don't await them
- await page.evaluate("() => new Promise(f => setTimeout(f, 1000))")
- await textarea.evaluate('e => e.style.display = "block"')
- await promise
- assert done == [False, True]
-
-
-async def test_a_nice_preview(page: Page, server: Server) -> None:
- await page.goto(f"{server.PREFIX}/dom.html")
- outer = await page.query_selector("#outer")
- inner = await page.query_selector("#inner")
- assert inner
- check = await page.query_selector("#check")
- text = await inner.evaluate_handle("e => e.firstChild")
- await page.evaluate("1") # Give them a chance to calculate the preview.
- assert str(outer) == 'JSHandle@…
'
- assert str(inner) == 'JSHandle@Text,↵more text
'
- assert str(text) == "JSHandle@#text=Text,↵more text"
- assert str(check) == 'JSHandle@ '
-
-
-async def test_get_attribute(page: Page, server: Server) -> None:
- await page.goto(f"{server.PREFIX}/dom.html")
- handle = await page.query_selector("#outer")
- assert handle
- assert await handle.get_attribute("name") == "value"
- assert await page.get_attribute("#outer", "name") == "value"
-
-
-async def test_inner_html(page: Page, server: Server) -> None:
- await page.goto(f"{server.PREFIX}/dom.html")
- handle = await page.query_selector("#outer")
- assert handle
- assert await handle.inner_html() == 'Text,\nmore text
'
- assert await page.inner_html("#outer") == 'Text,\nmore text
'
-
-
-async def test_inner_text(page: Page, server: Server) -> None:
- await page.goto(f"{server.PREFIX}/dom.html")
- handle = await page.query_selector("#inner")
- assert handle
- assert await handle.inner_text() == "Text, more text"
- assert await page.inner_text("#inner") == "Text, more text"
-
-
-async def test_inner_text_should_throw(page: Page, server: Server) -> None:
- await page.set_content("text ")
- with pytest.raises(Error) as exc_info1:
- await page.inner_text("svg")
- assert " Node is not an HTMLElement" in exc_info1.value.message
-
- handle = await page.query_selector("svg")
- assert handle
- with pytest.raises(Error) as exc_info2:
- await handle.inner_text()
- assert " Node is not an HTMLElement" in exc_info2.value.message
-
-
-async def test_text_content(page: Page, server: Server) -> None:
- await page.goto(f"{server.PREFIX}/dom.html")
- handle = await page.query_selector("#inner")
- assert handle
- assert await handle.text_content() == "Text,\nmore text"
- assert await page.text_content("#inner") == "Text,\nmore text"
-
-
-async def test_check_the_box(page: Page) -> None:
- await page.set_content(' ')
- input = await page.query_selector("input")
- assert input
- await input.check()
- assert await page.evaluate("checkbox.checked")
-
-
-async def test_uncheck_the_box(page: Page) -> None:
- await page.set_content(' ')
- input = await page.query_selector("input")
- assert input
- await input.uncheck()
- assert await page.evaluate("checkbox.checked") is False
-
-
-async def test_select_single_option(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/select.html")
- select = await page.query_selector("select")
- assert select
- await select.select_option(value="blue")
- assert await page.evaluate("result.onInput") == ["blue"]
- assert await page.evaluate("result.onChange") == ["blue"]
-
-
-async def test_focus_a_button(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/button.html")
- button = await page.query_selector("button")
- assert button
- assert await button.evaluate("button => document.activeElement === button") is False
- await button.focus()
- assert await button.evaluate("button => document.activeElement === button")
-
-
-async def test_is_visible_and_is_hidden_should_work(page: Page) -> None:
- await page.set_content("Hi
")
- div = await page.query_selector("div")
- assert div
- assert await div.is_visible()
- assert await div.is_hidden() is False
- assert await page.is_visible("div")
- assert await page.is_hidden("div") is False
- span = await page.query_selector("span")
- assert span
- assert await span.is_visible() is False
- assert await span.is_hidden()
- assert await page.is_visible("span") is False
- assert await page.is_hidden("span")
-
-
-async def test_is_enabled_and_is_disabled_should_work(page: Page) -> None:
- await page.set_content(
- """
- button1
- button2
- div
- """
- )
- div = await page.query_selector("div")
- assert div
- assert await div.is_enabled()
- assert await div.is_disabled() is False
- assert await page.is_enabled("div")
- assert await page.is_disabled("div") is False
- button1 = await page.query_selector(":text('button1')")
- assert button1
- assert await button1.is_enabled() is False
- assert await button1.is_disabled()
- assert await page.is_enabled(":text('button1')") is False
- assert await page.is_disabled(":text('button1')")
- button2 = await page.query_selector(":text('button2')")
- assert button2
- assert await button2.is_enabled()
- assert await button2.is_disabled() is False
- assert await page.is_enabled(":text('button2')")
- assert await page.is_disabled(":text('button2')") is False
-
-
-async def test_is_editable_should_work(page: Page) -> None:
- await page.set_content(" ")
- await page.eval_on_selector("textarea", "t => t.readOnly = true")
- input1 = await page.query_selector("#input1")
- assert input1
- assert await input1.is_editable() is False
- assert await page.is_editable("#input1") is False
- input2 = await page.query_selector("#input2")
- assert input2
- assert await input2.is_editable()
- assert await page.is_editable("#input2")
- textarea = await page.query_selector("textarea")
- assert textarea
- assert await textarea.is_editable() is False
- assert await page.is_editable("textarea") is False
-
-
-async def test_is_checked_should_work(page: Page) -> None:
- await page.set_content('Not a checkbox
')
- handle = await page.query_selector("input")
- assert handle
- assert await handle.is_checked()
- assert await page.is_checked("input")
- await handle.evaluate("input => input.checked = false")
- assert await handle.is_checked() is False
- assert await page.is_checked("input") is False
- with pytest.raises(Error) as exc_info:
- await page.is_checked("div")
- assert "Not a checkbox or radio button" in exc_info.value.message
-
-
-async def test_input_value(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/textarea.html")
- element = await page.query_selector("input")
- assert element
- await element.fill("my-text-content")
- assert await element.input_value() == "my-text-content"
-
- await element.fill("")
- assert await element.input_value() == ""
-
-
-async def test_set_checked(page: Page) -> None:
- await page.set_content("` `")
- input = await page.query_selector("input")
- assert input
- await input.set_checked(True)
- assert await page.evaluate("checkbox.checked")
- await input.set_checked(False)
- assert await page.evaluate("checkbox.checked") is False
-
-
-async def test_should_allow_disposing_twice(page: Page) -> None:
- await page.set_content("")
- element = await page.query_selector("section")
- assert element
- await element.dispose()
- await element.dispose()
diff --git a/tests/async/test_element_handle_wait_for_element_state.py b/tests/async/test_element_handle_wait_for_element_state.py
deleted file mode 100644
index 2ad39f4..0000000
--- a/tests/async/test_element_handle_wait_for_element_state.py
+++ /dev/null
@@ -1,156 +0,0 @@
-# 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
-from typing import List
-
-import pytest
-
-from playwright.async_api import ElementHandle, Error, Page
-from tests.server import Server
-
-
-async def give_it_a_chance_to_resolve(page: Page) -> None:
- for i in range(5):
- await page.evaluate(
- "() => new Promise(f => requestAnimationFrame(() => requestAnimationFrame(f)))"
- )
-
-
-async def wait_for_state(div: ElementHandle, state: str, done: List[bool]) -> None:
- await div.wait_for_element_state(state) # type: ignore
- done[0] = True
-
-
-async def wait_for_state_to_throw(div: ElementHandle, state: str) -> pytest.ExceptionInfo[Error]:
- with pytest.raises(Error) as exc_info:
- await div.wait_for_element_state(state) # type: ignore
- return exc_info
-
-
-async def test_should_wait_for_visible(page: Page) -> None:
- await page.set_content('content
')
- div = await page.query_selector("div")
- assert div
- done = [False]
- promise = asyncio.create_task(wait_for_state(div, "visible", done))
- await give_it_a_chance_to_resolve(page)
- assert done[0] is False
- assert div
- await div.evaluate('div => div.style.display = "block"')
- await promise
-
-
-async def test_should_wait_for_already_visible(page: Page) -> None:
- await page.set_content("content
")
- div = await page.query_selector("div")
- assert div
- await div.wait_for_element_state("visible")
-
-
-async def test_should_timeout_waiting_for_visible(page: Page) -> None:
- await page.set_content('content
')
- div = await page.query_selector("div")
- assert div
- with pytest.raises(Error) as exc_info:
- await div.wait_for_element_state("visible", timeout=1000)
- assert "Timeout 1000ms exceeded" in exc_info.value.message
-
-
-async def test_should_throw_waiting_for_visible_when_detached(page: Page) -> None:
- await page.set_content('content
')
- div = await page.query_selector("div")
- assert div
- promise = asyncio.create_task(wait_for_state_to_throw(div, "visible"))
- await div.evaluate("div => div.remove()")
- exc_info = await promise
- assert "Element is not attached to the DOM" in exc_info.value.message
-
-
-async def test_should_wait_for_hidden(page: Page) -> None:
- await page.set_content("content
")
- div = await page.query_selector("div")
- assert div
- done = [False]
- promise = asyncio.create_task(wait_for_state(div, "hidden", done))
- await give_it_a_chance_to_resolve(page)
- assert done[0] is False
- await div.evaluate('div => div.style.display = "none"')
- await promise
-
-
-async def test_should_wait_for_already_hidden(page: Page) -> None:
- await page.set_content("
")
- div = await page.query_selector("div")
- assert div
- await div.wait_for_element_state("hidden")
-
-
-async def test_should_wait_for_hidden_when_detached(page: Page) -> None:
- await page.set_content("content
")
- div = await page.query_selector("div")
- assert div
- done = [False]
- promise = asyncio.create_task(wait_for_state(div, "hidden", done))
- await give_it_a_chance_to_resolve(page)
- assert done[0] is False
- assert div
- await div.evaluate("div => div.remove()")
- await promise
-
-
-async def test_should_wait_for_enabled_button(page: Page, server: Server) -> None:
- await page.set_content("Target ")
- span = await page.query_selector("text=Target")
- assert span
- done = [False]
- promise = asyncio.create_task(wait_for_state(span, "enabled", done))
- await give_it_a_chance_to_resolve(page)
- assert done[0] is False
- await span.evaluate("span => span.parentElement.disabled = false")
- await promise
-
-
-async def test_should_throw_waiting_for_enabled_when_detached(page: Page) -> None:
- await page.set_content("Target ")
- button = await page.query_selector("button")
- assert button
- promise = asyncio.create_task(wait_for_state_to_throw(button, "enabled"))
- await button.evaluate("button => button.remove()")
- exc_info = await promise
- assert "Element is not attached to the DOM" in exc_info.value.message
-
-
-async def test_should_wait_for_disabled_button(page: Page) -> None:
- await page.set_content("Target ")
- span = await page.query_selector("text=Target")
- assert span
- done = [False]
- promise = asyncio.create_task(wait_for_state(span, "disabled", done))
- await give_it_a_chance_to_resolve(page)
- assert done[0] is False
- await span.evaluate("span => span.parentElement.disabled = true")
- await promise
-
-
-async def test_should_wait_for_editable_input(page: Page, server: Server) -> None:
- await page.set_content(" ")
- input = await page.query_selector("input")
- assert input
- done = [False]
- promise = asyncio.create_task(wait_for_state(input, "editable", done))
- await give_it_a_chance_to_resolve(page)
- assert done[0] is False
- await input.evaluate("input => input.readOnly = false")
- await promise
diff --git a/tests/async/test_emulation_focus.py b/tests/async/test_emulation_focus.py
deleted file mode 100644
index 782b8ac..0000000
--- a/tests/async/test_emulation_focus.py
+++ /dev/null
@@ -1,173 +0,0 @@
-# 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
-from typing import Callable
-
-import pytest
-from playwright.async_api import Page
-
-from tests.server import Server
-
-from .utils import Utils
-
-
-async def test_should_think_that_it_is_focused_by_default(page: Page) -> None:
- assert await page.evaluate("document.hasFocus()")
-
-
-async def test_should_think_that_all_pages_are_focused(page: Page) -> None:
- page2 = await page.context.new_page()
- assert await page.evaluate("document.hasFocus()")
- assert await page2.evaluate("document.hasFocus()")
- await page2.close()
-
-
-async def test_should_focus_popups_by_default(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- async with page.expect_popup() as popup_info:
- await page.evaluate("url => { window.open(url); }", server.EMPTY_PAGE)
- popup = await popup_info.value
- assert await popup.evaluate("document.hasFocus()")
- assert await page.evaluate("document.hasFocus()")
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_should_provide_target_for_keyboard_events(page: Page, server: Server) -> None:
- page2 = await page.context.new_page()
- await asyncio.gather(
- page.goto(server.PREFIX + "/input/textarea.html"),
- page2.goto(server.PREFIX + "/input/textarea.html"),
- )
- await asyncio.gather(
- page.focus("input"),
- page2.focus("input"),
- )
- text = "first"
- text2 = "second"
- await asyncio.gather(
- page.keyboard.type(text),
- page2.keyboard.type(text2),
- )
- results = await asyncio.gather(
- page.evaluate("result"),
- page2.evaluate("result"),
- )
- assert results == [text, text2]
-
-
-async def test_should_not_affect_mouse_event_target_page(page: Page, server: Server) -> None:
- page2 = await page.context.new_page()
- click_counter = """() => {
- document.onclick = () => window.click_count = (window.click_count || 0) + 1;
- }"""
- await asyncio.gather(
- page.evaluate(click_counter),
- page2.evaluate(click_counter),
- page.focus("body"),
- page2.focus("body"),
- )
- await asyncio.gather(
- page.mouse.click(1, 1),
- page2.mouse.click(1, 1),
- )
- counters = await asyncio.gather(
- page.evaluate("window.click_count"),
- page2.evaluate("window.click_count"),
- )
- assert counters == [1, 1]
-
-
-async def test_should_change_document_activeElement(page: Page, server: Server) -> None:
- page2 = await page.context.new_page()
- await asyncio.gather(
- page.goto(server.PREFIX + "/input/textarea.html"),
- page2.goto(server.PREFIX + "/input/textarea.html"),
- )
- await asyncio.gather(
- page.focus("input"),
- page2.focus("textarea"),
- )
- active = await asyncio.gather(
- page.evaluate("document.activeElement.tagName"),
- page2.evaluate("document.activeElement.tagName"),
- )
- assert active == ["INPUT", "TEXTAREA"]
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_should_not_affect_screenshots(
- page: Page, server: Server, assert_to_be_golden: Callable[[bytes, str], None]
-) -> None:
- # Firefox headed produces a different image.
- page2 = await page.context.new_page()
- await asyncio.gather(
- page.set_viewport_size({"width": 500, "height": 500}),
- page.goto(server.PREFIX + "/grid.html"),
- page2.set_viewport_size({"width": 50, "height": 50}),
- page2.goto(server.PREFIX + "/grid.html"),
- )
- await asyncio.gather(
- page.focus("body"),
- page2.focus("body"),
- )
- screenshots = await asyncio.gather(
- page.screenshot(),
- page2.screenshot(),
- )
- assert_to_be_golden(screenshots[0], "screenshot-sanity.png")
- assert_to_be_golden(screenshots[1], "grid-cell-0.png")
-
-
-async def test_should_change_focused_iframe(page: Page, server: Server, utils: Utils) -> None:
- await page.goto(server.EMPTY_PAGE)
- [frame1, frame2] = await asyncio.gather(
- utils.attach_frame(page, "frame1", server.PREFIX + "/input/textarea.html"),
- utils.attach_frame(page, "frame2", server.PREFIX + "/input/textarea.html"),
- )
- logger = """() => {
- self._events = [];
- const element = document.querySelector('input');
- element.onfocus = element.onblur = (e) => self._events.push(e.type);
- }"""
- await asyncio.gather(
- frame1.evaluate(logger),
- frame2.evaluate(logger),
- )
- focused = await asyncio.gather(
- frame1.evaluate("document.hasFocus()"),
- frame2.evaluate("document.hasFocus()"),
- )
- assert focused == [False, False]
- await frame1.focus("input")
- events = await asyncio.gather(
- frame1.evaluate("self._events"),
- frame2.evaluate("self._events"),
- )
- assert events == [["focus"], []]
- focused = await asyncio.gather(
- frame1.evaluate("document.hasFocus()"),
- frame2.evaluate("document.hasFocus()"),
- )
- assert focused == [True, False]
- await frame2.focus("input")
- events = await asyncio.gather(
- frame1.evaluate("self._events"),
- frame2.evaluate("self._events"),
- )
- assert events == [["focus", "blur"], ["focus"]]
- focused = await asyncio.gather(
- frame1.evaluate("document.hasFocus()"),
- frame2.evaluate("document.hasFocus()"),
- )
- assert focused == [False, True]
diff --git a/tests/async/test_expect_misc.py b/tests/async/test_expect_misc.py
deleted file mode 100644
index 8dd0639..0000000
--- a/tests/async/test_expect_misc.py
+++ /dev/null
@@ -1,76 +0,0 @@
-# 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 pytest
-
-from playwright.async_api import Page, TimeoutError, expect
-from tests.server import Server
-
-
-async def test_to_be_in_viewport_should_work(page: Page, server: Server) -> None:
- await page.set_content(
- """
-
- foo
- """
- )
- await expect(page.locator("#big")).to_be_in_viewport()
- await expect(page.locator("#small")).not_to_be_in_viewport()
- await page.locator("#small").scroll_into_view_if_needed()
- await expect(page.locator("#small")).to_be_in_viewport()
- await expect(page.locator("#small")).to_be_in_viewport(ratio=1)
-
-
-async def test_to_be_in_viewport_should_respect_ratio_option(page: Page, server: Server) -> None:
- await page.set_content(
- """
-
-
- """
- )
- await expect(page.locator("div")).to_be_in_viewport()
- await expect(page.locator("div")).to_be_in_viewport(ratio=0.1)
- await expect(page.locator("div")).to_be_in_viewport(ratio=0.2)
-
- await expect(page.locator("div")).to_be_in_viewport(ratio=0.25)
- # In this test, element's ratio is 0.25.
- await expect(page.locator("div")).not_to_be_in_viewport(ratio=0.26)
-
- await expect(page.locator("div")).not_to_be_in_viewport(ratio=0.3)
- await expect(page.locator("div")).not_to_be_in_viewport(ratio=0.7)
- await expect(page.locator("div")).not_to_be_in_viewport(ratio=0.8)
-
-
-async def test_to_be_in_viewport_should_have_good_stack(page: Page, server: Server) -> None:
- with pytest.raises(AssertionError) as exc_info:
- await expect(page.locator("body")).not_to_be_in_viewport(timeout=100)
- assert 'unexpected value "viewport ratio' in str(exc_info.value)
-
-
-async def test_to_be_in_viewport_should_report_intersection_even_if_fully_covered_by_other_element(
- page: Page, server: Server
-) -> None:
- await page.set_content(
- """
- hello
- None:
- with pytest.raises(TimeoutError) as exc_info:
- await page.wait_for_selector("#not-found", timeout=1)
- assert exc_info.value.name == "TimeoutError"
diff --git a/tests/async/test_fetch_browser_context.py b/tests/async/test_fetch_browser_context.py
deleted file mode 100644
index 26eecc6..0000000
--- a/tests/async/test_fetch_browser_context.py
+++ /dev/null
@@ -1,314 +0,0 @@
-# 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 base64
-import json
-from typing import Any, Callable, cast
-from urllib.parse import parse_qs
-
-import pytest
-from playwright.async_api import Browser, BrowserContext, Error, FilePayload, Page
-
-from tests.server import Server, TestServerRequest
-from tests.utils import must
-
-
-async def test_get_should_work(context: BrowserContext, server: Server) -> None:
- response = await context.request.get(server.PREFIX + "/simple.json")
- assert response.url == server.PREFIX + "/simple.json"
- assert response.status == 200
- assert response.status_text == "OK"
- assert response.ok is True
- assert response.headers["content-type"] == "application/json"
- assert {
- "name": "Content-Type",
- "value": "application/json",
- } in response.headers_array
- assert await response.text() == '{"foo": "bar"}\n'
-
-
-async def test_fetch_should_work(context: BrowserContext, server: Server) -> None:
- response = await context.request.fetch(server.PREFIX + "/simple.json")
- assert response.url == server.PREFIX + "/simple.json"
- assert response.status == 200
- assert response.status_text == "OK"
- assert response.ok is True
- assert response.headers["content-type"] == "application/json"
- assert {
- "name": "Content-Type",
- "value": "application/json",
- } in response.headers_array
- assert await response.text() == '{"foo": "bar"}\n'
-
-
-async def test_should_throw_on_network_error(context: BrowserContext, server: Server) -> None:
- server.set_route("/test", lambda request: request.loseConnection())
- with pytest.raises(Error, match="socket hang up"):
- await context.request.fetch(server.PREFIX + "/test")
-
-
-async def test_should_add_session_cookies_to_request(
- context: BrowserContext, server: Server
-) -> None:
- await context.add_cookies(
- [
- {
- "name": "username",
- "value": "John Doe",
- "url": server.EMPTY_PAGE,
- "expires": -1,
- "httpOnly": False,
- "secure": False,
- "sameSite": "Lax",
- }
- ]
- )
- [server_req, response] = await asyncio.gather(
- server.wait_for_request("/empty.html"),
- context.request.get(server.EMPTY_PAGE),
- )
- assert server_req.getHeader("Cookie") == "username=John Doe"
-
-
-@pytest.mark.parametrize("method", ["fetch", "delete", "get", "head", "patch", "post", "put"])
-async def test_should_support_query_params(
- context: BrowserContext, server: Server, method: str
-) -> None:
- expected_params = {"p1": "v1", "парам2": "знач2"}
- [server_req, _] = await asyncio.gather(
- server.wait_for_request("/empty.html"),
- getattr(context.request, method)(server.EMPTY_PAGE + "?p1=foo", params=expected_params),
- )
- assert server_req.args["p1".encode()][0].decode() == "v1"
- assert len(server_req.args["p1".encode()]) == 1
- assert server_req.args["парам2".encode()][0].decode() == "знач2"
-
-
-@pytest.mark.parametrize("method", ["fetch", "delete", "get", "head", "patch", "post", "put"])
-async def test_should_support_fail_on_status_code(
- context: BrowserContext, server: Server, method: str
-) -> None:
- with pytest.raises(Error, match="404 Not Found"):
- await getattr(context.request, method)(
- server.PREFIX + "/this-does-clearly-not-exist.html",
- fail_on_status_code=True,
- )
-
-
-@pytest.mark.parametrize("method", ["fetch", "delete", "get", "head", "patch", "post", "put"])
-async def test_should_support_ignore_https_errors_option(
- context: BrowserContext, https_server: Server, method: str
-) -> None:
- response = await getattr(context.request, method)(
- https_server.EMPTY_PAGE, ignore_https_errors=True
- )
- assert response.ok
- assert response.status == 200
-
-
-async def test_should_not_add_context_cookie_if_cookie_header_passed_as_parameter(
- context: BrowserContext, server: Server
-) -> None:
- await context.add_cookies(
- [
- {
- "name": "username",
- "value": "John Doe",
- "url": server.EMPTY_PAGE,
- "expires": -1,
- "httpOnly": False,
- "secure": False,
- "sameSite": "Lax",
- }
- ]
- )
- [server_req, _] = await asyncio.gather(
- server.wait_for_request("/empty.html"),
- context.request.get(server.EMPTY_PAGE, headers={"Cookie": "foo=bar"}),
- )
- assert server_req.getHeader("Cookie") == "foo=bar"
-
-
-async def test_should_support_http_credentials_send_immediately_for_browser_context(
- context_factory: "Callable[..., asyncio.Future[BrowserContext]]", server: Server
-) -> None:
- context = await context_factory(
- http_credentials={
- "username": "user",
- "password": "pass",
- "origin": server.PREFIX.upper(),
- "send": "always",
- }
- )
- # First request
- server_request, response = await asyncio.gather(
- server.wait_for_request("/empty.html"), context.request.get(server.EMPTY_PAGE)
- )
- expected_auth = "Basic " + base64.b64encode(b"user:pass").decode()
- assert server_request.getHeader("authorization") == expected_auth
- assert response.status == 200
-
- # Second request
- server_request, response = await asyncio.gather(
- server.wait_for_request("/empty.html"),
- context.request.get(server.CROSS_PROCESS_PREFIX + "/empty.html"),
- )
- # Not sent to another origin.
- assert server_request.getHeader("authorization") is None
- assert response.status == 200
-
-
-async def test_support_http_credentials_send_immediately_for_browser_new_page(
- server: Server, browser: Browser
-) -> None:
- page = await browser.new_page(
- http_credentials={
- "username": "user",
- "password": "pass",
- "origin": server.PREFIX.upper(),
- "send": "always",
- }
- )
- server_request, response = await asyncio.gather(
- server.wait_for_request("/empty.html"), page.request.get(server.EMPTY_PAGE)
- )
- assert (
- server_request.getHeader("authorization")
- == "Basic " + base64.b64encode(b"user:pass").decode()
- )
- assert response.status == 200
-
- server_request, response = await asyncio.gather(
- server.wait_for_request("/empty.html"),
- page.request.get(server.CROSS_PROCESS_PREFIX + "/empty.html"),
- )
- # Not sent to another origin.
- assert server_request.getHeader("authorization") is None
- assert response.status == 200
-
- await page.close()
-
-
-@pytest.mark.parametrize("method", ["delete", "patch", "post", "put"])
-async def test_should_support_post_data(
- context: BrowserContext, method: str, server: Server
-) -> None:
- async def support_post_data(fetch_data: Any, request_post_data: Any) -> None:
- [request, response] = await asyncio.gather(
- server.wait_for_request("/simple.json"),
- getattr(context.request, method)(server.PREFIX + "/simple.json", data=fetch_data),
- )
- assert request.method.decode() == method.upper()
- assert request.post_body == request_post_data
- assert response.status == 200
- assert response.url == server.PREFIX + "/simple.json"
- assert request.getHeader("Content-Length") == str(len(must(request.post_body)))
-
- await support_post_data("My request", "My request".encode())
- await support_post_data(b"My request", "My request".encode())
- await support_post_data(["my", "request"], json.dumps(["my", "request"]).encode())
- await support_post_data({"my": "request"}, json.dumps({"my": "request"}).encode())
- with pytest.raises(Error, match="Unsupported 'data' type:
"):
- await support_post_data(lambda: None, None)
-
-
-async def test_should_support_application_x_www_form_urlencoded(
- context: BrowserContext, server: Server
-) -> None:
- [request, response] = await asyncio.gather(
- server.wait_for_request("/empty.html"),
- context.request.post(
- server.PREFIX + "/empty.html",
- form={
- "firstName": "John",
- "lastName": "Doe",
- "file": "f.js",
- },
- ),
- )
- assert request.method == b"POST"
- assert request.getHeader("Content-Type") == "application/x-www-form-urlencoded"
- assert request.post_body
- body = request.post_body.decode()
- assert request.getHeader("Content-Length") == str(len(body))
- params = parse_qs(request.post_body)
- assert params[b"firstName"] == [b"John"]
- assert params[b"lastName"] == [b"Doe"]
- assert params[b"file"] == [b"f.js"]
-
-
-async def test_should_support_multipart_form_data(context: BrowserContext, server: Server) -> None:
- file: FilePayload = {
- "name": "f.js",
- "mimeType": "text/javascript",
- "buffer": b"var x = 10;\r\n;console.log(x);",
- }
- [request, _] = await asyncio.gather(
- server.wait_for_request("/empty.html"),
- context.request.post(
- server.PREFIX + "/empty.html",
- multipart={
- "firstName": "John",
- "lastName": "Doe",
- "file": file,
- },
- ),
- )
- assert request.method == b"POST"
- assert cast(str, request.getHeader("Content-Type")).startswith("multipart/form-data; ")
- assert must(request.getHeader("Content-Length")) == str(len(must(request.post_body)))
- assert request.args[b"firstName"] == [b"John"]
- assert request.args[b"lastName"] == [b"Doe"]
- assert request.args[b"file"][0] == file["buffer"]
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_should_add_default_headers(
- context: BrowserContext, page: Page, server: Server
-) -> None:
- [request, response] = await asyncio.gather(
- server.wait_for_request("/empty.html"),
- context.request.get(server.EMPTY_PAGE),
- )
- assert request.getHeader("Accept") == "*/*"
- assert request.getHeader("Accept-Encoding") == "gzip,deflate,br"
- assert request.getHeader("User-Agent") == await page.evaluate("() => navigator.userAgent")
-
-
-async def test_should_work_after_context_dispose(context: BrowserContext, server: Server) -> None:
- await context.close(reason="Test ended.")
- with pytest.raises(Error, match="Test ended."):
- await context.request.get(server.EMPTY_PAGE)
-
-
-async def test_should_retry_ECONNRESET(context: BrowserContext, server: Server) -> None:
- request_count = 0
-
- def _handle_request(req: TestServerRequest) -> None:
- nonlocal request_count
- request_count += 1
- if request_count <= 3:
- assert req.transport
- req.transport.abortConnection()
- return
- req.setHeader("content-type", "text/plain")
- req.write(b"Hello!")
- req.finish()
-
- server.set_route("/test", _handle_request)
- response = await context.request.fetch(server.PREFIX + "/test", max_retries=3)
- assert response.status == 200
- assert await response.text() == "Hello!"
- assert request_count == 4
diff --git a/tests/async/test_fetch_global.py b/tests/async/test_fetch_global.py
deleted file mode 100644
index 6a5e2d3..0000000
--- a/tests/async/test_fetch_global.py
+++ /dev/null
@@ -1,472 +0,0 @@
-# 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 base64
-import json
-import sys
-from pathlib import Path
-from typing import Any
-from urllib.parse import urlparse
-
-import pytest
-
-from playwright.async_api import APIResponse, Error, Playwright, StorageState
-from tests.server import Server, TestServerRequest
-
-
-@pytest.mark.parametrize("method", ["fetch", "delete", "get", "head", "patch", "post", "put"])
-async def test_should_work(playwright: Playwright, method: str, server: Server) -> None:
- request = await playwright.request.new_context()
- response: APIResponse = await getattr(request, method)(server.PREFIX + "/simple.json")
- assert response.status == 200
- assert response.status_text == "OK"
- assert response.ok is True
- assert response.url == server.PREFIX + "/simple.json"
- assert response.headers["content-type"] == "application/json"
- assert {
- "name": "Content-Type",
- "value": "application/json",
- } in response.headers_array
- assert await response.text() == ("" if method == "head" else '{"foo": "bar"}\n')
-
-
-async def test_should_dispose_global_request(playwright: Playwright, server: Server) -> None:
- request = await playwright.request.new_context()
- response = await request.get(server.PREFIX + "/simple.json")
- assert await response.json() == {"foo": "bar"}
- await response.dispose()
- with pytest.raises(Error, match="Response has been disposed"):
- await response.body()
-
-
-async def test_should_dispose_with_custom_error_message(
- playwright: Playwright, server: Server
-) -> None:
- request = await playwright.request.new_context()
- await request.dispose(reason="My reason")
- with pytest.raises(Error, match="My reason"):
- await request.get(server.EMPTY_PAGE)
-
-
-async def test_should_support_global_user_agent_option(
- playwright: Playwright, server: Server
-) -> None:
- api_request_context = await playwright.request.new_context(user_agent="My Agent")
- response = await api_request_context.get(server.PREFIX + "/empty.html")
- [request, _] = await asyncio.gather(
- server.wait_for_request("/empty.html"),
- api_request_context.get(server.EMPTY_PAGE),
- )
- assert response.ok is True
- assert response.url == server.EMPTY_PAGE
- assert request.getHeader("user-agent") == "My Agent"
-
-
-async def test_should_support_global_timeout_option(playwright: Playwright, server: Server) -> None:
- request = await playwright.request.new_context(timeout=100)
- server.set_route("/empty.html", lambda req: None)
- with pytest.raises(Error, match="Request timed out after 100ms"):
- await request.get(server.EMPTY_PAGE)
-
-
-async def test_should_propagate_extra_http_headers_with_redirects(
- playwright: Playwright, server: Server
-) -> None:
- server.set_redirect("/a/redirect1", "/b/c/redirect2")
- server.set_redirect("/b/c/redirect2", "/simple.json")
- request = await playwright.request.new_context(extra_http_headers={"My-Secret": "Value"})
- [req1, req2, req3, _] = await asyncio.gather(
- server.wait_for_request("/a/redirect1"),
- server.wait_for_request("/b/c/redirect2"),
- server.wait_for_request("/simple.json"),
- request.get(f"{server.PREFIX}/a/redirect1"),
- )
- assert req1.getHeader("my-secret") == "Value"
- assert req2.getHeader("my-secret") == "Value"
- assert req3.getHeader("my-secret") == "Value"
-
-
-async def test_should_support_global_http_credentials_option(
- playwright: Playwright, server: Server
-) -> None:
- server.set_auth("/empty.html", "user", "pass")
- request1 = await playwright.request.new_context()
- response1 = await request1.get(server.EMPTY_PAGE)
- assert response1.status == 401
- await response1.dispose()
-
- request2 = await playwright.request.new_context(
- http_credentials={"username": "user", "password": "pass"}
- )
- response2 = await request2.get(server.EMPTY_PAGE)
- assert response2.status == 200
- assert response2.ok is True
- await response2.dispose()
-
-
-async def test_should_return_error_with_wrong_credentials(
- playwright: Playwright, server: Server
-) -> None:
- server.set_auth("/empty.html", "user", "pass")
- request = await playwright.request.new_context(
- http_credentials={"username": "user", "password": "wrong"}
- )
- response = await request.get(server.EMPTY_PAGE)
- assert response.status == 401
- assert response.ok is False
-
-
-async def test_should_work_with_correct_credentials_and_matching_origin(
- playwright: Playwright, server: Server
-) -> None:
- server.set_auth("/empty.html", "user", "pass")
- request = await playwright.request.new_context(
- http_credentials={
- "username": "user",
- "password": "pass",
- "origin": server.PREFIX,
- }
- )
- response = await request.get(server.EMPTY_PAGE)
- assert response.status == 200
- await response.dispose()
-
-
-async def test_should_work_with_correct_credentials_and_matching_origin_case_insensitive(
- playwright: Playwright, server: Server
-) -> None:
- server.set_auth("/empty.html", "user", "pass")
- request = await playwright.request.new_context(
- http_credentials={
- "username": "user",
- "password": "pass",
- "origin": server.PREFIX.upper(),
- }
- )
- response = await request.get(server.EMPTY_PAGE)
- assert response.status == 200
- await response.dispose()
-
-
-async def test_should_return_error_with_correct_credentials_and_mismatching_scheme(
- playwright: Playwright, server: Server
-) -> None:
- server.set_auth("/empty.html", "user", "pass")
- request = await playwright.request.new_context(
- http_credentials={
- "username": "user",
- "password": "pass",
- "origin": server.PREFIX.replace("http://", "https://"),
- }
- )
- response = await request.get(server.EMPTY_PAGE)
- assert response.status == 401
- await response.dispose()
-
-
-async def test_should_return_error_with_correct_credentials_and_mismatching_hostname(
- playwright: Playwright, server: Server
-) -> None:
- server.set_auth("/empty.html", "user", "pass")
- hostname = urlparse(server.PREFIX).hostname
- assert hostname
- origin = server.PREFIX.replace(hostname, "mismatching-hostname")
- request = await playwright.request.new_context(
- http_credentials={"username": "user", "password": "pass", "origin": origin}
- )
- response = await request.get(server.EMPTY_PAGE)
- assert response.status == 401
- await response.dispose()
-
-
-async def test_should_return_error_with_correct_credentials_and_mismatching_port(
- playwright: Playwright, server: Server
-) -> None:
- server.set_auth("/empty.html", "user", "pass")
- origin = server.PREFIX.replace(str(server.PORT), str(server.PORT + 1))
- request = await playwright.request.new_context(
- http_credentials={"username": "user", "password": "pass", "origin": origin}
- )
- response = await request.get(server.EMPTY_PAGE)
- assert response.status == 401
- await response.dispose()
-
-
-async def test_support_http_credentials_send_immediately(
- playwright: Playwright, server: Server
-) -> None:
- request = await playwright.request.new_context(
- http_credentials={
- "username": "user",
- "password": "pass",
- "origin": server.PREFIX.upper(),
- "send": "always",
- }
- )
- server_request, response = await asyncio.gather(
- server.wait_for_request("/empty.html"), request.get(server.EMPTY_PAGE)
- )
- assert (
- server_request.getHeader("authorization")
- == "Basic " + base64.b64encode(b"user:pass").decode()
- )
- assert response.status == 200
-
- server_request, response = await asyncio.gather(
- server.wait_for_request("/empty.html"),
- request.get(server.CROSS_PROCESS_PREFIX + "/empty.html"),
- )
- # Not sent to another origin.
- assert server_request.getHeader("authorization") is None
- assert response.status == 200
-
-
-async def test_should_support_global_ignore_https_errors_option(
- playwright: Playwright, https_server: Server
-) -> None:
- request = await playwright.request.new_context(ignore_https_errors=True)
- response = await request.get(https_server.EMPTY_PAGE)
- assert response.status == 200
- assert response.ok is True
- assert response.url == https_server.EMPTY_PAGE
- await response.dispose()
-
-
-async def test_should_resolve_url_relative_to_global_base_url_option(
- playwright: Playwright, server: Server
-) -> None:
- request = await playwright.request.new_context(base_url=server.PREFIX)
- response = await request.get("/empty.html")
- assert response.status == 200
- assert response.ok is True
- assert response.url == server.EMPTY_PAGE
- await response.dispose()
-
-
-async def test_should_use_playwright_as_a_user_agent(
- playwright: Playwright, server: Server
-) -> None:
- request = await playwright.request.new_context()
- [server_req, _] = await asyncio.gather(
- server.wait_for_request("/empty.html"),
- request.get(server.EMPTY_PAGE),
- )
- assert str(server_req.getHeader("User-Agent")).startswith("Playwright/")
- await request.dispose()
-
-
-async def test_should_return_empty_body(playwright: Playwright, server: Server) -> None:
- request = await playwright.request.new_context()
- response = await request.get(server.EMPTY_PAGE)
- body = await response.body()
- assert len(body) == 0
- assert await response.text() == ""
- await request.dispose()
- with pytest.raises(Error, match="Response has been disposed"):
- await response.body()
-
-
-async def test_storage_state_should_round_trip_through_file(
- playwright: Playwright, tmpdir: Path
-) -> None:
- expected: StorageState = {
- "cookies": [
- {
- "name": "a",
- "value": "b",
- "domain": "a.b.one.com",
- "path": "/",
- "expires": -1,
- "httpOnly": False,
- "secure": False,
- "sameSite": "Lax",
- }
- ],
- "origins": [],
- }
- request = await playwright.request.new_context(storage_state=expected)
- path = tmpdir / "storage-state.json"
- actual = await request.storage_state(path=path)
- assert actual == expected
-
- written = path.read_text("utf8")
- assert json.loads(written) == expected
-
- request2 = await playwright.request.new_context(storage_state=path)
- state2 = await request2.storage_state()
- assert state2 == expected
-
-
-serialization_data = [
- [{"foo": "bar"}],
- [["foo", "bar", 2021]],
- ["foo"],
- [True],
- [2021],
-]
-
-
-@pytest.mark.parametrize("serialization", serialization_data)
-async def test_should_json_stringify_body_when_content_type_is_application_json(
- playwright: Playwright, server: Server, serialization: Any
-) -> None:
- request = await playwright.request.new_context()
- [req, _] = await asyncio.gather(
- server.wait_for_request("/empty.html"),
- request.post(
- server.EMPTY_PAGE,
- headers={"content-type": "application/json"},
- data=serialization,
- ),
- )
- body = req.post_body
- assert body
- assert body.decode() == json.dumps(serialization)
- await request.dispose()
-
-
-@pytest.mark.parametrize("serialization", serialization_data)
-async def test_should_not_double_stringify_body_when_content_type_is_application_json(
- playwright: Playwright, server: Server, serialization: Any
-) -> None:
- request = await playwright.request.new_context()
- stringified_value = json.dumps(serialization)
- [req, _] = await asyncio.gather(
- server.wait_for_request("/empty.html"),
- request.post(
- server.EMPTY_PAGE,
- headers={"content-type": "application/json"},
- data=stringified_value,
- ),
- )
-
- body = req.post_body
- assert body
- assert body.decode() == stringified_value
- await request.dispose()
-
-
-async def test_should_accept_already_serialized_data_as_bytes_when_content_type_is_application_json(
- playwright: Playwright, server: Server
-) -> None:
- request = await playwright.request.new_context()
- stringified_value = json.dumps({"foo": "bar"}).encode()
- [req, _] = await asyncio.gather(
- server.wait_for_request("/empty.html"),
- request.post(
- server.EMPTY_PAGE,
- headers={"content-type": "application/json"},
- data=stringified_value,
- ),
- )
- body = req.post_body
- assert body == stringified_value
- await request.dispose()
-
-
-async def test_should_contain_default_user_agent(playwright: Playwright, server: Server) -> None:
- request = await playwright.request.new_context()
- [server_request, _] = await asyncio.gather(
- server.wait_for_request("/empty.html"),
- request.get(server.EMPTY_PAGE),
- )
- user_agent = server_request.getHeader("user-agent")
- assert user_agent
- assert "python" in user_agent
- assert f"{sys.version_info.major}.{sys.version_info.minor}" in user_agent
-
-
-async def test_should_throw_an_error_when_max_redirects_is_exceeded(
- playwright: Playwright, server: Server
-) -> None:
- server.set_redirect("/a/redirect1", "/b/c/redirect2")
- server.set_redirect("/b/c/redirect2", "/b/c/redirect3")
- server.set_redirect("/b/c/redirect3", "/b/c/redirect4")
- server.set_redirect("/b/c/redirect4", "/simple.json")
-
- request = await playwright.request.new_context()
- for method in ["GET", "PUT", "POST", "OPTIONS", "HEAD", "PATCH"]:
- for max_redirects in [1, 2, 3]:
- with pytest.raises(Error) as exc_info:
- await request.fetch(
- server.PREFIX + "/a/redirect1",
- method=method,
- max_redirects=max_redirects,
- )
- assert "Max redirect count exceeded" in str(exc_info)
-
-
-async def test_should_not_follow_redirects_when_max_redirects_is_set_to_0(
- playwright: Playwright, server: Server
-) -> None:
- server.set_redirect("/a/redirect1", "/b/c/redirect2")
- server.set_redirect("/b/c/redirect2", "/simple.json")
-
- request = await playwright.request.new_context()
- for method in ["GET", "PUT", "POST", "OPTIONS", "HEAD", "PATCH"]:
- response = await request.fetch(
- server.PREFIX + "/a/redirect1", method=method, max_redirects=0
- )
- assert response.headers["location"] == "/b/c/redirect2"
- assert response.status == 302
-
-
-async def test_should_throw_an_error_when_max_redirects_is_less_than_0(
- playwright: Playwright,
- server: Server,
-) -> None:
- request = await playwright.request.new_context()
- for method in ["GET", "PUT", "POST", "OPTIONS", "HEAD", "PATCH"]:
- with pytest.raises(AssertionError) as exc_info:
- await request.fetch(server.PREFIX + "/a/redirect1", method=method, max_redirects=-1)
- assert "'max_redirects' must be greater than or equal to '0'" in str(exc_info)
-
-
-async def test_should_serialize_request_data(playwright: Playwright, server: Server) -> None:
- request = await playwright.request.new_context()
- server.set_route("/echo", lambda req: (req.write(req.post_body), req.finish()))
- for data, expected in [
- ({"foo": None}, '{"foo": null}'),
- ([], "[]"),
- ({}, "{}"),
- ("", ""),
- ]:
- response = await request.post(server.PREFIX + "/echo", data=data)
- assert response.status == 200
- assert await response.text() == expected
- await request.dispose()
-
-
-async def test_should_retry_ECONNRESET(playwright: Playwright, server: Server) -> None:
- request_count = 0
-
- def _handle_request(req: TestServerRequest) -> None:
- nonlocal request_count
- request_count += 1
- if request_count <= 3:
- assert req.transport
- req.transport.abortConnection()
- return
- req.setHeader("content-type", "text/plain")
- req.write(b"Hello!")
- req.finish()
-
- server.set_route("/test", _handle_request)
- request = await playwright.request.new_context()
- response = await request.fetch(server.PREFIX + "/test", max_retries=3)
- assert response.status == 200
- assert await response.text() == "Hello!"
- assert request_count == 4
- await request.dispose()
diff --git a/tests/async/test_fill.py.disabled b/tests/async/test_fill.py.disabled
deleted file mode 100644
index 4dd6db3..0000000
--- a/tests/async/test_fill.py.disabled
+++ /dev/null
@@ -1,31 +0,0 @@
-# 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.
-
-from playwright.async_api import Page
-from tests.server import Server
-
-
-async def test_fill_textarea(page: Page, server: Server) -> None:
- await page.goto(f"{server.PREFIX}/input/textarea.html")
- await page.fill("textarea", "some value")
- assert await page.evaluate("result") == "some value"
-
-
-#
-
-
-async def test_fill_input(page: Page, server: Server) -> None:
- await page.goto(f"{server.PREFIX}/input/textarea.html")
- await page.fill("input", "some value")
- assert await page.evaluate("result") == "some value"
diff --git a/tests/async/test_focus.py.disabled b/tests/async/test_focus.py.disabled
deleted file mode 100644
index 72698ea..0000000
--- a/tests/async/test_focus.py.disabled
+++ /dev/null
@@ -1,110 +0,0 @@
-# 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 pytest
-
-from playwright.async_api import Page
-
-
-async def test_should_work(page: Page) -> None:
- await page.set_content("
")
- assert await page.evaluate("() => document.activeElement.nodeName") == "BODY"
- await page.focus("#d1")
- assert await page.evaluate("() => document.activeElement.id") == "d1"
-
-
-async def test_should_emit_focus_event(page: Page) -> None:
- await page.set_content("
")
- focused = []
- await page.expose_function("focusEvent", lambda: focused.append(True))
- await page.evaluate("() => d1.addEventListener('focus', focusEvent)")
- await page.focus("#d1")
- assert focused == [True]
-
-
-async def test_should_emit_blur_event(page: Page) -> None:
- await page.set_content(
- "DIV1
DIV2
"
- )
- await page.focus("#d1")
- focused = []
- blurred = []
- await page.expose_function("focusEvent", lambda: focused.append(True))
- await page.expose_function("blurEvent", lambda: blurred.append(True))
- await page.evaluate("() => d1.addEventListener('blur', blurEvent)")
- await page.evaluate("() => d2.addEventListener('focus', focusEvent)")
- await page.focus("#d2")
- assert focused == [True]
- assert blurred == [True]
-
-
-async def test_should_traverse_focus(page: Page) -> None:
- await page.set_content(' ')
- focused = []
- await page.expose_function("focusEvent", lambda: focused.append(True))
- await page.evaluate("() => i2.addEventListener('focus', focusEvent)")
-
- await page.focus("#i1")
- await page.keyboard.type("First")
- await page.keyboard.press("Tab")
- await page.keyboard.type("Last")
-
- assert focused == [True]
- assert await page.eval_on_selector("#i1", "e => e.value") == "First"
- assert await page.eval_on_selector("#i2", "e => e.value") == "Last"
-
-
-async def test_should_traverse_focus_in_all_directions(page: Page) -> None:
- await page.set_content(' ')
- await page.keyboard.press("Tab")
- assert await page.evaluate("() => document.activeElement.value") == "1"
- await page.keyboard.press("Tab")
- assert await page.evaluate("() => document.activeElement.value") == "2"
- await page.keyboard.press("Tab")
- assert await page.evaluate("() => document.activeElement.value") == "3"
- await page.keyboard.press("Shift+Tab")
- assert await page.evaluate("() => document.activeElement.value") == "2"
- await page.keyboard.press("Shift+Tab")
- assert await page.evaluate("() => document.activeElement.value") == "1"
-
-
-@pytest.mark.only_platform("darwin")
-@pytest.mark.only_browser("webkit")
-async def test_should_traverse_only_form_elements(page: Page) -> None:
- await page.set_content(
- """
-
- button
- link
-
- """
- )
- await page.keyboard.press("Tab")
- assert await page.evaluate("() => document.activeElement.id") == "input-1"
- await page.keyboard.press("Tab")
- assert await page.evaluate("() => document.activeElement.id") == "input-2"
- await page.keyboard.press("Shift+Tab")
- assert await page.evaluate("() => document.activeElement.id") == "input-1"
- await page.keyboard.press("Alt+Tab")
- assert await page.evaluate("() => document.activeElement.id") == "button"
- await page.keyboard.press("Alt+Tab")
- assert await page.evaluate("() => document.activeElement.id") == "link"
- await page.keyboard.press("Alt+Tab")
- assert await page.evaluate("() => document.activeElement.id") == "input-2"
- await page.keyboard.press("Alt+Shift+Tab")
- assert await page.evaluate("() => document.activeElement.id") == "link"
- await page.keyboard.press("Alt+Shift+Tab")
- assert await page.evaluate("() => document.activeElement.id") == "button"
- await page.keyboard.press("Alt+Shift+Tab")
- assert await page.evaluate("() => document.activeElement.id") == "input-1"
diff --git a/tests/async/test_frames.py b/tests/async/test_frames.py
deleted file mode 100644
index 8deb70c..0000000
--- a/tests/async/test_frames.py
+++ /dev/null
@@ -1,280 +0,0 @@
-# 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
-from typing import Optional
-
-import pytest
-
-from playwright.async_api import Error, Page
-from tests.server import Server
-
-from .utils import Utils
-
-
-async def test_evaluate_handle(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- main_frame = page.main_frame
- assert main_frame.page == page
- window_handle = await main_frame.evaluate_handle("window")
- assert window_handle
-
-
-async def test_frame_element(page: Page, server: Server, utils: Utils) -> None:
- await page.goto(server.EMPTY_PAGE)
- frame1 = await utils.attach_frame(page, "frame1", server.EMPTY_PAGE)
- assert frame1
- await utils.attach_frame(page, "frame2", server.EMPTY_PAGE)
- frame3 = await utils.attach_frame(page, "frame3", server.EMPTY_PAGE)
- assert frame3
- frame1handle1 = await page.query_selector("#frame1")
- assert frame1handle1
- frame1handle2 = await frame1.frame_element()
- frame3handle1 = await page.query_selector("#frame3")
- assert frame3handle1
- frame3handle2 = await frame3.frame_element()
- assert await frame1handle1.evaluate("(a, b) => a === b", frame1handle2)
- assert await frame3handle1.evaluate("(a, b) => a === b", frame3handle2)
- assert await frame1handle1.evaluate("(a, b) => a === b", frame3handle1) is False
-
-
-async def test_frame_element_with_content_frame(page: Page, server: Server, utils: Utils) -> None:
- await page.goto(server.EMPTY_PAGE)
- frame = await utils.attach_frame(page, "frame1", server.EMPTY_PAGE)
- handle = await frame.frame_element()
- content_frame = await handle.content_frame()
- assert content_frame == frame
-
-
-async def test_frame_element_throw_when_detached(page: Page, server: Server, utils: Utils) -> None:
- await page.goto(server.EMPTY_PAGE)
- frame1 = await utils.attach_frame(page, "frame1", server.EMPTY_PAGE)
- await page.eval_on_selector("#frame1", "e => e.remove()")
- error: Optional[Error] = None
- try:
- await frame1.frame_element()
- except Error as e:
- error = e
- assert error
- assert error.message == "Frame.frame_element: Frame has been detached."
-
-
-async def test_evaluate_throw_for_detached_frames(page: Page, server: Server, utils: Utils) -> None:
- frame1 = await utils.attach_frame(page, "frame1", server.EMPTY_PAGE)
- assert frame1
- await utils.detach_frame(page, "frame1")
- error: Optional[Error] = None
- try:
- await frame1.evaluate("7 * 8")
- except Error as e:
- error = e
- assert error
- assert "Frame was detached" in error.message
-
-
-async def test_evaluate_isolated_between_frames(page: Page, server: Server, utils: Utils) -> None:
- await page.goto(server.EMPTY_PAGE)
- await utils.attach_frame(page, "frame1", server.EMPTY_PAGE)
- assert len(page.frames) == 2
- [frame1, frame2] = page.frames
- assert frame1 != frame2
-
- await asyncio.gather(frame1.evaluate("window.a = 1"), frame2.evaluate("window.a = 2"))
- [a1, a2] = await asyncio.gather(frame1.evaluate("window.a"), frame2.evaluate("window.a"))
- assert a1 == 1
- assert a2 == 2
-
-
-async def test_should_handle_nested_frames(page: Page, server: Server, utils: Utils) -> None:
- await page.goto(server.PREFIX + "/frames/nested-frames.html")
- assert utils.dump_frames(page.main_frame) == [
- "http://localhost:/frames/nested-frames.html",
- " http://localhost:/frames/frame.html (aframe)",
- " http://localhost:/frames/two-frames.html (2frames)",
- " http://localhost:/frames/frame.html (dos)",
- " http://localhost:/frames/frame.html (uno)",
- ]
-
-
-async def test_should_send_events_when_frames_are_manipulated_dynamically(
- page: Page, server: Server, utils: Utils
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- # validate frameattached events
- attached_frames = []
- page.on("frameattached", lambda frame: attached_frames.append(frame))
- await utils.attach_frame(page, "frame1", "./assets/frame.html")
- assert len(attached_frames) == 1
- assert "/assets/frame.html" in attached_frames[0].url
-
- # validate framenavigated events
- navigated_frames = []
- page.on("framenavigated", lambda frame: navigated_frames.append(frame))
- await page.evaluate(
- """() => {
- frame = document.getElementById('frame1')
- frame.src = './empty.html'
- return new Promise(x => frame.onload = x)
- }"""
- )
-
- assert len(navigated_frames) == 1
- assert navigated_frames[0].url == server.EMPTY_PAGE
-
- # validate framedetached events
- detached_frames = []
- page.on("framedetached", lambda frame: detached_frames.append(frame))
- await utils.detach_frame(page, "frame1")
- assert len(detached_frames) == 1
- assert detached_frames[0].is_detached()
-
-
-async def test_framenavigated_when_navigating_on_anchor_urls(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- async with page.expect_event("framenavigated"):
- await page.goto(server.EMPTY_PAGE + "#foo")
- assert page.url == server.EMPTY_PAGE + "#foo"
-
-
-async def test_persist_main_frame_on_cross_process_navigation(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- main_frame = page.main_frame
- await page.goto(server.CROSS_PROCESS_PREFIX + "/empty.html")
- assert page.main_frame == main_frame
-
-
-async def test_should_not_send_attach_detach_events_for_main_frame(
- page: Page, server: Server
-) -> None:
- has_events = []
- page.on("frameattached", lambda frame: has_events.append(True))
- page.on("framedetached", lambda frame: has_events.append(True))
- await page.goto(server.EMPTY_PAGE)
- assert has_events == []
-
-
-async def test_detach_child_frames_on_navigation(page: Page, server: Server) -> None:
- attached_frames = []
- detached_frames = []
- navigated_frames = []
- page.on("frameattached", lambda frame: attached_frames.append(frame))
- page.on("framedetached", lambda frame: detached_frames.append(frame))
- page.on("framenavigated", lambda frame: navigated_frames.append(frame))
- await page.goto(server.PREFIX + "/frames/nested-frames.html")
- assert len(attached_frames) == 4
- assert len(detached_frames) == 0
- assert len(navigated_frames) == 5
-
- attached_frames = []
- detached_frames = []
- navigated_frames = []
- await page.goto(server.EMPTY_PAGE)
- assert len(attached_frames) == 0
- assert len(detached_frames) == 4
- assert len(navigated_frames) == 1
-
-
-async def test_framesets(page: Page, server: Server) -> None:
- attached_frames = []
- detached_frames = []
- navigated_frames = []
- page.on("frameattached", lambda frame: attached_frames.append(frame))
- page.on("framedetached", lambda frame: detached_frames.append(frame))
- page.on("framenavigated", lambda frame: navigated_frames.append(frame))
- await page.goto(server.PREFIX + "/frames/frameset.html")
- assert len(attached_frames) == 4
- assert len(detached_frames) == 0
- assert len(navigated_frames) == 5
-
- attached_frames = []
- detached_frames = []
- navigated_frames = []
- await page.goto(server.EMPTY_PAGE)
- assert len(attached_frames) == 0
- assert len(detached_frames) == 4
- assert len(navigated_frames) == 1
-
-
-async def test_frame_from_inside_shadow_dom(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/shadow.html")
- await page.evaluate(
- """async url => {
- frame = document.createElement('iframe');
- frame.src = url;
- document.body.shadowRoot.appendChild(frame);
- await new Promise(x => frame.onload = x);
- }""",
- server.EMPTY_PAGE,
- )
- assert len(page.frames) == 2
- assert page.frames[1].url == server.EMPTY_PAGE
-
-
-async def test_frame_name(page: Page, server: Server, utils: Utils) -> None:
- await utils.attach_frame(page, "theFrameId", server.EMPTY_PAGE)
- await page.evaluate(
- """url => {
- frame = document.createElement('iframe');
- frame.name = 'theFrameName';
- frame.src = url;
- document.body.appendChild(frame);
- return new Promise(x => frame.onload = x);
- }""",
- server.EMPTY_PAGE,
- )
- assert page.frames[0].name == ""
- assert page.frames[1].name == "theFrameId"
- assert page.frames[2].name == "theFrameName"
-
-
-async def test_frame_parent(page: Page, server: Server, utils: Utils) -> None:
- await utils.attach_frame(page, "frame1", server.EMPTY_PAGE)
- await utils.attach_frame(page, "frame2", server.EMPTY_PAGE)
- assert page.frames[0].parent_frame is None
- assert page.frames[1].parent_frame == page.main_frame
- assert page.frames[2].parent_frame == page.main_frame
-
-
-async def test_should_report_different_frame_instance_when_frame_re_attaches(
- page: Page, server: Server, utils: Utils
-) -> None:
- frame1 = await utils.attach_frame(page, "frame1", server.EMPTY_PAGE)
- await page.evaluate(
- """() => {
- window.frame = document.querySelector('#frame1')
- window.frame.remove()
- }"""
- )
-
- assert frame1.is_detached()
- async with page.expect_event("frameattached") as frame2_info:
- await page.evaluate("() => document.body.appendChild(window.frame)")
-
- frame2 = await frame2_info.value
- assert frame2.is_detached() is False
- assert frame1 != frame2
-
-
-async def test_strict_mode(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- await page.set_content(
- """
- Hello
- Hello
- """
- )
- with pytest.raises(Error):
- await page.text_content("button", strict=True)
- with pytest.raises(Error):
- await page.query_selector("button", strict=True)
diff --git a/tests/async/test_geolocation.py b/tests/async/test_geolocation.py
deleted file mode 100644
index 3e4832d..0000000
--- a/tests/async/test_geolocation.py
+++ /dev/null
@@ -1,136 +0,0 @@
-# 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 pytest
-from playwright.async_api import Browser, BrowserContext, Error, Page
-
-from tests.server import Server
-
-
-async def test_should_work(page: Page, server: Server, context: BrowserContext) -> None:
- await context.grant_permissions(["geolocation"])
- await page.goto(server.EMPTY_PAGE)
- await context.set_geolocation({"latitude": 10, "longitude": 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: BrowserContext) -> None:
- with pytest.raises(Error) as exc:
- await context.set_geolocation({"latitude": 10, "longitude": 200})
- assert (
- "geolocation.longitude: precondition -180 <= LONGITUDE <= 180 failed." in exc.value.message
- )
-
-
-async def test_should_isolate_contexts(
- page: Page, server: Server, context: BrowserContext, browser: Browser
-) -> None:
- await context.grant_permissions(["geolocation"])
- await context.set_geolocation({"latitude": 10, "longitude": 10})
- await page.goto(server.EMPTY_PAGE)
-
- context2 = await browser.new_context(
- permissions=["geolocation"], geolocation={"latitude": 20, "longitude": 20}
- )
-
- page2 = await context2.new_page()
- 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_use_context_options(browser: Browser, server: Server) -> None:
- context = await browser.new_context(
- geolocation={"latitude": 10, "longitude": 10}, permissions=["geolocation"]
- )
- page = await context.new_page()
- 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_watch_position_should_be_notified(
- page: Page, server: Server, context: BrowserContext
-) -> None:
- await context.grant_permissions(["geolocation"])
- await page.goto(server.EMPTY_PAGE)
- messages = []
- page.on("console", lambda message: messages.append(message.text))
-
- await context.set_geolocation({"latitude": 0, "longitude": 0})
- await page.evaluate(
- """() => {
- navigator.geolocation.watchPosition(pos => {
- const coords = pos.coords;
- console.log(`lat=${coords.latitude} lng=${coords.longitude}`);
- }, err => {});
- }"""
- )
-
- async with page.expect_console_message(lambda m: "lat=0 lng=10" in m.text):
- await context.set_geolocation({"latitude": 0, "longitude": 10})
-
- async with page.expect_console_message(lambda m: "lat=20 lng=30" in m.text):
- await context.set_geolocation({"latitude": 20, "longitude": 30})
-
- async with page.expect_console_message(lambda m: "lat=40 lng=50" in m.text):
- await context.set_geolocation({"latitude": 40, "longitude": 50})
-
- all_messages = "|".join(messages)
- assert "lat=0 lng=10" in all_messages
- assert "lat=20 lng=30" in all_messages
- assert "lat=40 lng=50" in all_messages
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_should_use_context_options_for_popup(
- page: Page, context: BrowserContext, server: Server
-) -> None:
- await context.grant_permissions(["geolocation"])
- await context.set_geolocation({"latitude": 10, "longitude": 10})
- async with page.expect_popup() as popup_info:
- await page.evaluate(
- "url => window._popup = window.open(url)",
- server.PREFIX + "/geolocation.html",
- )
- popup = await popup_info.value
- await popup.wait_for_load_state()
- geolocation = await popup.evaluate("() => window.geolocationPromise")
- assert geolocation == {"latitude": 10, "longitude": 10}
diff --git a/tests/async/test_har.py b/tests/async/test_har.py
deleted file mode 100644
index 7ad7f0d..0000000
--- a/tests/async/test_har.py
+++ /dev/null
@@ -1,750 +0,0 @@
-# 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 json
-import os
-import re
-import zipfile
-from pathlib import Path
-from typing import Awaitable, Callable, cast
-
-import pytest
-from playwright.async_api import Browser, BrowserContext, Error, Page, Route, expect
-
-from tests.server import Server, TestServerRequest
-from tests.utils import must
-
-
-async def test_should_work(browser: Browser, server: Server, tmpdir: Path) -> None:
- path = os.path.join(tmpdir, "log.har")
- context = await browser.new_context(record_har_path=path)
- page = await context.new_page()
- await page.goto(server.EMPTY_PAGE)
- await context.close()
- with open(path) as f:
- data = json.load(f)
- assert "log" in data
-
-
-async def test_should_omit_content(browser: Browser, server: Server, tmpdir: Path) -> None:
- path = os.path.join(tmpdir, "log.har")
- context = await browser.new_context(
- record_har_path=path,
- record_har_content="omit",
- )
- page = await context.new_page()
- await page.goto(server.PREFIX + "/har.html")
- await context.close()
- with open(path) as f:
- data = json.load(f)
- assert "log" in data
- log = data["log"]
- content1 = log["entries"][0]["response"]["content"]
- assert "text" not in content1
- assert "encoding" not in content1
-
-
-async def test_should_omit_content_legacy(browser: Browser, server: Server, tmpdir: Path) -> None:
- path = os.path.join(tmpdir, "log.har")
- context = await browser.new_context(record_har_path=path, record_har_omit_content=True)
- page = await context.new_page()
- await page.goto(server.PREFIX + "/har.html")
- await context.close()
- with open(path) as f:
- data = json.load(f)
- assert "log" in data
- log = data["log"]
- content1 = log["entries"][0]["response"]["content"]
- assert "text" not in content1
- assert "encoding" not in content1
-
-
-async def test_should_attach_content(browser: Browser, server: Server, tmpdir: Path) -> None:
- path = os.path.join(tmpdir, "log.har.zip")
- context = await browser.new_context(
- record_har_path=path,
- record_har_content="attach",
- )
- page = await context.new_page()
- await page.goto(server.PREFIX + "/har.html")
- await page.evaluate("() => fetch('/pptr.png').then(r => r.arrayBuffer())")
- await context.close()
- with zipfile.ZipFile(path) as z:
- with z.open("har.har") as har:
- entries = json.load(har)["log"]["entries"]
-
- assert "encoding" not in entries[0]["response"]["content"]
- assert entries[0]["response"]["content"]["mimeType"] == "text/html; charset=utf-8"
- assert (
- "75841480e2606c03389077304342fac2c58ccb1b"
- in entries[0]["response"]["content"]["_file"]
- )
- assert entries[0]["response"]["content"]["size"] >= 96
- assert entries[0]["response"]["content"]["compression"] == 0
-
- assert "encoding" not in entries[1]["response"]["content"]
- assert entries[1]["response"]["content"]["mimeType"] == "text/css; charset=utf-8"
- assert (
- "79f739d7bc88e80f55b9891a22bf13a2b4e18adb"
- in entries[1]["response"]["content"]["_file"]
- )
- assert entries[1]["response"]["content"]["size"] >= 37
- assert entries[1]["response"]["content"]["compression"] == 0
-
- assert "encoding" not in entries[2]["response"]["content"]
- assert entries[2]["response"]["content"]["mimeType"] == "image/png"
- assert (
- "a4c3a18f0bb83f5d9fe7ce561e065c36205762fa"
- in entries[2]["response"]["content"]["_file"]
- )
- assert entries[2]["response"]["content"]["size"] >= 6000
- assert entries[2]["response"]["content"]["compression"] == 0
-
- with z.open("75841480e2606c03389077304342fac2c58ccb1b.html") as f:
- assert b"HAR Page" in f.read()
-
- with z.open("79f739d7bc88e80f55b9891a22bf13a2b4e18adb.css") as f:
- assert b"pink" in f.read()
-
- with z.open("a4c3a18f0bb83f5d9fe7ce561e065c36205762fa.png") as f:
- assert len(f.read()) == entries[2]["response"]["content"]["size"]
-
-
-async def test_should_not_omit_content(browser: Browser, server: Server, tmpdir: Path) -> None:
- path = os.path.join(tmpdir, "log.har")
- context = await browser.new_context(record_har_path=path, record_har_omit_content=False)
- page = await context.new_page()
- await page.goto(server.PREFIX + "/har.html")
- await context.close()
- with open(path) as f:
- data = json.load(f)
- content1 = data["log"]["entries"][0]["response"]["content"]
- assert "text" in content1
-
-
-async def test_should_include_content(browser: Browser, server: Server, tmpdir: Path) -> None:
- path = os.path.join(tmpdir, "log.har")
- context = await browser.new_context(record_har_path=path)
- page = await context.new_page()
- await page.goto(server.PREFIX + "/har.html")
- await context.close()
- with open(path) as f:
- data = json.load(f)
- assert "log" in data
- log = data["log"]
-
- content1 = log["entries"][0]["response"]["content"]
- assert content1["mimeType"] == "text/html; charset=utf-8"
- assert "HAR Page" in content1["text"]
-
-
-async def test_should_default_to_full_mode(browser: Browser, server: Server, tmpdir: Path) -> None:
- path = os.path.join(tmpdir, "log.har")
- context = await browser.new_context(
- record_har_path=path,
- )
- page = await context.new_page()
- await page.goto(server.PREFIX + "/har.html")
- await context.close()
- with open(path) as f:
- data = json.load(f)
- assert "log" in data
- log = data["log"]
- assert log["entries"][0]["request"]["bodySize"] >= 0
-
-
-async def test_should_support_minimal_mode(browser: Browser, server: Server, tmpdir: Path) -> None:
- path = os.path.join(tmpdir, "log.har")
- context = await browser.new_context(
- record_har_path=path,
- record_har_mode="minimal",
- )
- page = await context.new_page()
- await page.goto(server.PREFIX + "/har.html")
- await context.close()
- with open(path) as f:
- data = json.load(f)
- assert "log" in data
- log = data["log"]
- assert log["entries"][0]["request"]["bodySize"] == -1
-
-
-async def test_should_filter_by_glob(browser: Browser, server: Server, tmpdir: str) -> None:
- path = os.path.join(tmpdir, "log.har")
- context = await browser.new_context(
- base_url=server.PREFIX,
- record_har_path=path,
- record_har_url_filter="/*.css",
- ignore_https_errors=True,
- )
- page = await context.new_page()
- await page.goto(server.PREFIX + "/har.html")
- await context.close()
- with open(path) as f:
- data = json.load(f)
- assert "log" in data
- log = data["log"]
- assert len(log["entries"]) == 1
- assert log["entries"][0]["request"]["url"].endswith("one-style.css")
-
-
-async def test_should_filter_by_regexp(browser: Browser, server: Server, tmpdir: str) -> None:
- path = os.path.join(tmpdir, "log.har")
- context = await browser.new_context(
- base_url=server.PREFIX,
- record_har_path=path,
- record_har_url_filter=re.compile("HAR.X?HTML", re.I),
- ignore_https_errors=True,
- )
- page = await context.new_page()
- await page.goto(server.PREFIX + "/har.html")
- await context.close()
- with open(path) as f:
- data = json.load(f)
- assert "log" in data
- log = data["log"]
- assert len(log["entries"]) == 1
- assert log["entries"][0]["request"]["url"].endswith("har.html")
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_should_context_route_from_har_matching_the_method_and_following_redirects(
- context: BrowserContext, assetdir: Path
-) -> None:
- await context.route_from_har(har=assetdir / "har-fulfill.har")
- page = await context.new_page()
- await page.goto("http://no.playwright/")
- # HAR contains a redirect for the script that should be followed automatically.
- assert await page.evaluate("window.value") == "foo"
- # HAR contains a POST for the css file that should not be used.
- await expect(page.locator("body")).to_have_css("background-color", "rgb(255, 0, 0)")
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_should_page_route_from_har_matching_the_method_and_following_redirects(
- page: Page, assetdir: Path
-) -> None:
- await page.route_from_har(har=assetdir / "har-fulfill.har")
- await page.goto("http://no.playwright/")
- # HAR contains a redirect for the script that should be followed automatically.
- assert await page.evaluate("window.value") == "foo"
- # HAR contains a POST for the css file that should not be used.
- await expect(page.locator("body")).to_have_css("background-color", "rgb(255, 0, 0)")
-
-
-async def test_fallback_continue_should_continue_when_not_found_in_har(
- context: BrowserContext, server: Server, assetdir: Path
-) -> None:
- await context.route_from_har(har=assetdir / "har-fulfill.har", not_found="fallback")
- page = await context.new_page()
- await page.goto(server.PREFIX + "/one-style.html")
- await expect(page.locator("body")).to_have_css("background-color", "rgb(255, 192, 203)")
-
-
-async def test_by_default_should_abort_requests_not_found_in_har(
- context: BrowserContext,
- server: Server,
- assetdir: Path,
- is_chromium: bool,
- is_webkit: bool,
-) -> None:
- await context.route_from_har(har=assetdir / "har-fulfill.har")
- page = await context.new_page()
-
- with pytest.raises(Error) as exc_info:
- await page.goto(server.EMPTY_PAGE)
- assert exc_info.value
- if is_chromium:
- assert "net::ERR_FAILED" in exc_info.value.message
- elif is_webkit:
- assert "Blocked by Web Inspector" in exc_info.value.message
- else:
- assert "NS_ERROR_FAILURE" in exc_info.value.message
-
-
-async def test_fallback_continue_should_continue_requests_on_bad_har(
- context: BrowserContext, server: Server, tmpdir: Path
-) -> None:
- path_to_invalid_har = tmpdir / "invalid.har"
- with path_to_invalid_har.open("w") as f:
- json.dump({"log": {}}, f)
- await context.route_from_har(har=path_to_invalid_har, not_found="fallback")
- page = await context.new_page()
- await page.goto(server.PREFIX + "/one-style.html")
- await expect(page.locator("body")).to_have_css("background-color", "rgb(255, 192, 203)")
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_should_only_handle_requests_matching_url_filter(
- context: BrowserContext, server: Server, assetdir: Path
-) -> None:
- await context.route_from_har(
- har=assetdir / "har-fulfill.har", not_found="fallback", url="**/*.js"
- )
- page = await context.new_page()
-
- async def handler(route: Route) -> None:
- assert route.request.url == "http://no.playwright/"
- await route.fulfill(
- status=200,
- content_type="text/html",
- body='hello
',
- )
-
- await context.route("http://no.playwright/", handler)
- await page.goto("http://no.playwright/")
- assert await page.evaluate("window.value") == "foo"
- await expect(page.locator("body")).to_have_css("background-color", "rgba(0, 0, 0, 0)")
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_should_only_handle_requests_matching_url_filter_no_fallback(
- context: BrowserContext, server: Server, assetdir: Path
-) -> None:
- await context.route_from_har(har=assetdir / "har-fulfill.har", url="**/*.js")
- page = await context.new_page()
-
- async def handler(route: Route) -> None:
- assert route.request.url == "http://no.playwright/"
- await route.fulfill(
- status=200,
- content_type="text/html",
- body='hello
',
- )
-
- await context.route("http://no.playwright/", handler)
- await page.goto("http://no.playwright/")
- assert await page.evaluate("window.value") == "foo"
- await expect(page.locator("body")).to_have_css("background-color", "rgba(0, 0, 0, 0)")
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_should_only_handle_requests_matching_url_filter_no_fallback_page(
- page: Page, server: Server, assetdir: Path
-) -> None:
- await page.route_from_har(har=assetdir / "har-fulfill.har", url="**/*.js")
-
- async def handler(route: Route) -> None:
- assert route.request.url == "http://no.playwright/"
- await route.fulfill(
- status=200,
- content_type="text/html",
- body='hello
',
- )
-
- await page.route("http://no.playwright/", handler)
- await page.goto("http://no.playwright/")
- assert await page.evaluate("window.value") == "foo"
- await expect(page.locator("body")).to_have_css("background-color", "rgba(0, 0, 0, 0)")
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_should_support_regex_filter(
- context: BrowserContext, server: Server, assetdir: Path
-) -> None:
- await context.route_from_har(
- har=assetdir / "har-fulfill.har",
- url=re.compile(r".*(\.js|.*\.css|no.playwright\/)"),
- )
- page = await context.new_page()
- await page.goto("http://no.playwright/")
- assert await page.evaluate("window.value") == "foo"
- await expect(page.locator("body")).to_have_css("background-color", "rgb(255, 0, 0)")
-
-
-async def test_should_change_document_url_after_redirected_navigation(
- context: BrowserContext, server: Server, assetdir: Path
-) -> None:
- await context.route_from_har(har=assetdir / "har-redirect.har")
- page = await context.new_page()
-
- async with page.expect_navigation() as navigation_info:
- await asyncio.gather(
- page.wait_for_url("https://www.theverge.com/"),
- page.goto("https://theverge.com/"),
- )
-
- response = await navigation_info.value
- await expect(page).to_have_url("https://www.theverge.com/")
- assert response.request.url == "https://www.theverge.com/"
- assert await page.evaluate("window.location.href") == "https://www.theverge.com/"
-
-
-async def test_should_change_document_url_after_redirected_navigation_on_click(
- context: BrowserContext, server: Server, assetdir: Path
-) -> None:
- await context.route_from_har(
- har=assetdir / "har-redirect.har", url=re.compile(r"/.*theverge.*/")
- )
- page = await context.new_page()
- await page.goto(server.EMPTY_PAGE)
- await page.set_content('click me ')
- async with page.expect_navigation() as navigation_info:
- await asyncio.gather(
- page.wait_for_url("https://www.theverge.com/"),
- page.click("text=click me"),
- )
-
- response = await navigation_info.value
- await expect(page).to_have_url("https://www.theverge.com/")
- assert response.request.url == "https://www.theverge.com/"
- assert await page.evaluate("window.location.href") == "https://www.theverge.com/"
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_should_go_back_to_redirected_navigation(
- context: BrowserContext, server: Server, assetdir: Path
-) -> None:
- await context.route_from_har(
- har=assetdir / "har-redirect.har", url=re.compile(r"/.*theverge.*/")
- )
- page = await context.new_page()
- await page.goto("https://theverge.com/")
- await page.goto(server.EMPTY_PAGE)
- await expect(page).to_have_url(server.EMPTY_PAGE)
-
- response = await page.go_back()
- assert response
- await expect(page).to_have_url("https://www.theverge.com/")
- assert response.request.url == "https://www.theverge.com/"
- assert await page.evaluate("window.location.href") == "https://www.theverge.com/"
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_should_go_forward_to_redirected_navigation(
- context: BrowserContext, server: Server, assetdir: Path
-) -> None:
- await context.route_from_har(
- har=assetdir / "har-redirect.har", url=re.compile(r"/.*theverge.*/")
- )
- page = await context.new_page()
- await page.goto("https://theverge.com/")
- await page.goto(server.EMPTY_PAGE)
- await expect(page).to_have_url(server.EMPTY_PAGE)
- await page.goto("https://theverge.com/")
- await expect(page).to_have_url("https://www.theverge.com/")
- await page.go_back()
- await expect(page).to_have_url(server.EMPTY_PAGE)
- response = await page.go_forward()
- assert response
- await expect(page).to_have_url("https://www.theverge.com/")
- assert response.request.url == "https://www.theverge.com/"
- assert await page.evaluate("window.location.href") == "https://www.theverge.com/"
-
-
-async def test_should_reload_redirected_navigation(
- context: BrowserContext, server: Server, assetdir: Path
-) -> None:
- await context.route_from_har(
- har=assetdir / "har-redirect.har", url=re.compile(r"/.*theverge.*/")
- )
- page = await context.new_page()
- await page.goto("https://theverge.com/")
- await expect(page).to_have_url("https://www.theverge.com/")
- response = await page.reload()
- assert response
- await expect(page).to_have_url("https://www.theverge.com/")
- assert response.request.url == "https://www.theverge.com/"
- assert await page.evaluate("window.location.href") == "https://www.theverge.com/"
-
-
-async def test_should_fulfill_from_har_with_content_in_a_file(
- context: BrowserContext, server: Server, assetdir: Path
-) -> None:
- await context.route_from_har(har=assetdir / "har-sha1.har")
- page = await context.new_page()
- await page.goto("http://no.playwright/")
- assert await page.content() == "Hello, world"
-
-
-async def test_should_round_trip_har_zip(
- browser: Browser, server: Server, assetdir: Path, tmpdir: Path
-) -> None:
- har_path = tmpdir / "har.zip"
- context_1 = await browser.new_context(record_har_mode="minimal", record_har_path=har_path)
- page_1 = await context_1.new_page()
- await page_1.goto(server.PREFIX + "/one-style.html")
- await context_1.close()
-
- context_2 = await browser.new_context()
- await context_2.route_from_har(har=har_path, not_found="abort")
- page_2 = await context_2.new_page()
- await page_2.goto(server.PREFIX + "/one-style.html")
- assert "hello, world!" in await page_2.content()
- await expect(page_2.locator("body")).to_have_css("background-color", "rgb(255, 192, 203)")
-
-
-async def test_should_round_trip_har_with_post_data(
- browser: Browser, server: Server, assetdir: Path, tmpdir: Path
-) -> None:
- server.set_route("/echo", lambda req: (req.write(req.post_body), req.finish()))
- fetch_function = """
- async (body) => {
- const response = await fetch('/echo', { method: 'POST', body });
- return await response.text();
- };
- """
- har_path = tmpdir / "har.zip"
- context_1 = await browser.new_context(record_har_mode="minimal", record_har_path=har_path)
- page_1 = await context_1.new_page()
- await page_1.goto(server.EMPTY_PAGE)
-
- assert await page_1.evaluate(fetch_function, "1") == "1"
- assert await page_1.evaluate(fetch_function, "2") == "2"
- assert await page_1.evaluate(fetch_function, "3") == "3"
- await context_1.close()
-
- context_2 = await browser.new_context()
- await context_2.route_from_har(har=har_path, not_found="abort")
- page_2 = await context_2.new_page()
- await page_2.goto(server.EMPTY_PAGE)
- assert await page_2.evaluate(fetch_function, "1") == "1"
- assert await page_2.evaluate(fetch_function, "2") == "2"
- assert await page_2.evaluate(fetch_function, "3") == "3"
- with pytest.raises(Exception):
- await page_2.evaluate(fetch_function, "4")
-
-
-async def test_should_disambiguate_by_header(
- browser: Browser, server: Server, tmpdir: Path
-) -> None:
- server.set_route(
- "/echo",
- lambda req: (req.write(cast(str, req.getHeader("baz")).encode()), req.finish()),
- )
- fetch_function = """
- async (bazValue) => {
- const response = await fetch('/echo', {
- method: 'POST',
- body: '',
- headers: {
- foo: 'foo-value',
- bar: 'bar-value',
- baz: bazValue,
- }
- });
- return await response.text();
- };
- """
- har_path = tmpdir / "har.zip"
- context_1 = await browser.new_context(record_har_mode="minimal", record_har_path=har_path)
- page_1 = await context_1.new_page()
- await page_1.goto(server.EMPTY_PAGE)
-
- assert await page_1.evaluate(fetch_function, "baz1") == "baz1"
- assert await page_1.evaluate(fetch_function, "baz2") == "baz2"
- assert await page_1.evaluate(fetch_function, "baz3") == "baz3"
- await context_1.close()
-
- context_2 = await browser.new_context()
- await context_2.route_from_har(har=har_path)
- page_2 = await context_2.new_page()
- await page_2.goto(server.EMPTY_PAGE)
- assert await page_2.evaluate(fetch_function, "baz1") == "baz1"
- assert await page_2.evaluate(fetch_function, "baz2") == "baz2"
- assert await page_2.evaluate(fetch_function, "baz3") == "baz3"
- assert await page_2.evaluate(fetch_function, "baz4") == "baz1"
-
-
-async def test_should_produce_extracted_zip(browser: Browser, server: Server, tmpdir: Path) -> None:
- har_path = tmpdir / "har.har"
- context = await browser.new_context(
- record_har_mode="minimal", record_har_path=har_path, record_har_content="attach"
- )
- page_1 = await context.new_page()
- await page_1.goto(server.PREFIX + "/one-style.html")
- await context.close()
-
- assert har_path.exists()
- with har_path.open() as r:
- content = r.read()
- assert "log" in content
- assert "background-color" not in r.read()
-
- context_2 = await browser.new_context()
- await context_2.route_from_har(har_path, not_found="abort")
- page_2 = await context_2.new_page()
- await page_2.goto(server.PREFIX + "/one-style.html")
- assert "hello, world!" in await page_2.content()
- await expect(page_2.locator("body")).to_have_css("background-color", "rgb(255, 192, 203)")
-
-
-async def test_should_update_har_zip_for_context(
- browser: Browser, server: Server, tmpdir: Path
-) -> None:
- har_path = tmpdir / "har.zip"
- context = await browser.new_context()
- await context.route_from_har(har_path, update=True)
- page_1 = await context.new_page()
- await page_1.goto(server.PREFIX + "/one-style.html")
- await context.close()
-
- assert har_path.exists()
-
- context_2 = await browser.new_context()
- await context_2.route_from_har(har_path, not_found="abort")
- page_2 = await context_2.new_page()
- await page_2.goto(server.PREFIX + "/one-style.html")
- assert "hello, world!" in await page_2.content()
- await expect(page_2.locator("body")).to_have_css("background-color", "rgb(255, 192, 203)")
-
-
-async def test_page_unroute_all_should_stop_page_route_from_har(
- context_factory: Callable[[], Awaitable[BrowserContext]],
- server: Server,
- assetdir: Path,
-) -> None:
- har_path = assetdir / "har-fulfill.har"
- context1 = await context_factory()
- page1 = await context1.new_page()
- # The har file contains requests for another domain, so the router
- # is expected to abort all requests.
- await page1.route_from_har(har_path, not_found="abort")
- with pytest.raises(Error) as exc_info:
- await page1.goto(server.EMPTY_PAGE)
- assert exc_info.value
- await page1.unroute_all(behavior="wait")
- response = must(await page1.goto(server.EMPTY_PAGE))
- assert response.ok
-
-
-async def test_context_unroute_call_should_stop_context_route_from_har(
- context_factory: Callable[[], Awaitable[BrowserContext]],
- server: Server,
- assetdir: Path,
-) -> None:
- har_path = assetdir / "har-fulfill.har"
- context1 = await context_factory()
- page1 = await context1.new_page()
- # The har file contains requests for another domain, so the router
- # is expected to abort all requests.
- await context1.route_from_har(har_path, not_found="abort")
- with pytest.raises(Error) as exc_info:
- await page1.goto(server.EMPTY_PAGE)
- assert exc_info.value
- await context1.unroute_all(behavior="wait")
- response = must(await page1.goto(server.EMPTY_PAGE))
- assert must(response).ok
-
-
-async def test_should_update_har_zip_for_page(
- browser: Browser, server: Server, tmpdir: Path
-) -> None:
- har_path = tmpdir / "har.zip"
- context = await browser.new_context()
- page_1 = await context.new_page()
- await page_1.route_from_har(har_path, update=True)
- await page_1.goto(server.PREFIX + "/one-style.html")
- await context.close()
-
- assert har_path.exists()
-
- context_2 = await browser.new_context()
- page_2 = await context_2.new_page()
- await page_2.route_from_har(har_path, not_found="abort")
- await page_2.goto(server.PREFIX + "/one-style.html")
- assert "hello, world!" in await page_2.content()
- await expect(page_2.locator("body")).to_have_css("background-color", "rgb(255, 192, 203)")
-
-
-async def test_should_update_har_zip_for_page_with_different_options(
- browser: Browser, server: Server, tmpdir: Path
-) -> None:
- har_path = tmpdir / "har.zip"
- context1 = await browser.new_context()
- page1 = await context1.new_page()
- await page1.route_from_har(har_path, update=True, update_content="embed", update_mode="full")
- await page1.goto(server.PREFIX + "/one-style.html")
- await context1.close()
-
- context2 = await browser.new_context()
- page2 = await context2.new_page()
- await page2.route_from_har(har_path, not_found="abort")
- await page2.goto(server.PREFIX + "/one-style.html")
- assert "hello, world!" in await page2.content()
- await expect(page2.locator("body")).to_have_css("background-color", "rgb(255, 192, 203)")
- await context2.close()
-
-
-async def test_should_update_extracted_har_zip_for_page(
- browser: Browser, server: Server, tmpdir: Path
-) -> None:
- har_path = tmpdir / "har.har"
- context = await browser.new_context()
- page_1 = await context.new_page()
- await page_1.route_from_har(har_path, update=True)
- await page_1.goto(server.PREFIX + "/one-style.html")
- await context.close()
-
- assert har_path.exists()
- with har_path.open() as r:
- content = r.read()
- assert "log" in content
- assert "background-color" not in r.read()
-
- context_2 = await browser.new_context()
- page_2 = await context_2.new_page()
- await page_2.route_from_har(har_path, not_found="abort")
- await page_2.goto(server.PREFIX + "/one-style.html")
- assert "hello, world!" in await page_2.content()
- await expect(page_2.locator("body")).to_have_css("background-color", "rgb(255, 192, 203)")
-
-
-async def test_should_ignore_aborted_requests(
- context_factory: Callable[[], Awaitable[BrowserContext]],
- server: Server,
- tmpdir: Path,
-) -> None:
- path = tmpdir / "test.har"
- server.set_route("/x", lambda request: request.loseConnection())
- context1 = await context_factory()
- await context1.route_from_har(har=path, update=True)
- page1 = await context1.new_page()
- await page1.goto(server.EMPTY_PAGE)
- req_promise = asyncio.create_task(server.wait_for_request("/x"))
- eval_task = asyncio.create_task(
- page1.evaluate("url => fetch(url).catch(e => 'cancelled')", server.PREFIX + "/x")
- )
- await req_promise
- req = await eval_task
- assert req == "cancelled"
- await context1.close()
-
- server.reset()
-
- def _handle_route(req: TestServerRequest) -> None:
- req.setHeader("Content-Type", "text/plain")
- req.write(b"test")
- req.finish()
-
- server.set_route("/x", _handle_route)
- context2 = await context_factory()
- await context2.route_from_har(path)
- page2 = await context2.new_page()
- await page2.goto(server.EMPTY_PAGE)
- eval_task = asyncio.create_task(
- page2.evaluate("url => fetch(url).catch(e => 'cancelled')", server.PREFIX + "/x")
- )
-
- async def _timeout() -> str:
- await asyncio.sleep(1)
- return "timeout"
-
- done, _ = await asyncio.wait(
- [eval_task, asyncio.create_task(_timeout())],
- return_when=asyncio.FIRST_COMPLETED,
- )
- assert next(iter(done)).result() == "timeout"
- eval_task.cancel()
diff --git a/tests/async/test_headful.py b/tests/async/test_headful.py
deleted file mode 100644
index d0bcd7f..0000000
--- a/tests/async/test_headful.py
+++ /dev/null
@@ -1,178 +0,0 @@
-# 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.
-
-
-from pathlib import Path
-from typing import Dict
-
-import pytest
-from playwright.async_api import BrowserType
-
-from tests.server import Server
-
-
-async def test_should_have_default_url_when_launching_browser(
- browser_type: BrowserType, launch_arguments: Dict, tmpdir: Path
-) -> None:
- browser_context = await browser_type.launch_persistent_context(
- tmpdir, **{**launch_arguments, "headless": False}
- )
- urls = [page.url for page in browser_context.pages]
- assert urls == ["about:blank"]
- await browser_context.close()
-
-
-async def test_should_close_browser_with_beforeunload_page(
- browser_type: BrowserType, launch_arguments: Dict, server: Server, tmpdir: Path
-) -> None:
- browser_context = await browser_type.launch_persistent_context(
- tmpdir, **{**launch_arguments, "headless": False}
- )
- page = await browser_context.new_page()
- await page.goto(server.PREFIX + "/beforeunload.html")
- # We have to interact with a page so that 'beforeunload' handlers
- # fire.
- await page.click("body")
- await browser_context.close()
-
-
-async def test_should_not_crash_when_creating_second_context(
- browser_type: BrowserType, launch_arguments: Dict, server: Server
-) -> None:
- browser = await browser_type.launch(**{**launch_arguments, "headless": False})
- browser_context = await browser.new_context()
- await browser_context.new_page()
- await browser_context.close()
- browser_context = await browser.new_context()
- await browser_context.new_page()
- await browser_context.close()
- await browser.close()
-
-
-async def test_should_click_background_tab(
- browser_type: BrowserType, launch_arguments: Dict, server: Server
-) -> None:
- browser = await browser_type.launch(**{**launch_arguments, "headless": False})
- page = await browser.new_page()
- await page.set_content(
- f'Hello empty.html '
- )
- await page.click("a")
- await page.click("button")
- await browser.close()
-
-
-async def test_should_close_browser_after_context_menu_was_triggered(
- browser_type: BrowserType, launch_arguments: Dict, server: Server
-) -> None:
- browser = await browser_type.launch(**{**launch_arguments, "headless": False})
- page = await browser.new_page()
- await page.goto(server.PREFIX + "/grid.html")
- await page.click("body", button="right")
- await browser.close()
-
-
-async def test_should_not_block_third_party_cookies(
- browser_type: BrowserType,
- launch_arguments: Dict,
- server: Server,
- is_chromium: bool,
- is_firefox: bool,
-) -> None:
- browser = await browser_type.launch(**{**launch_arguments, "headless": False})
- page = await browser.new_page()
- await page.goto(server.EMPTY_PAGE)
- await page.evaluate(
- """src => {
- let fulfill;
- const promise = new Promise(x => fulfill = x);
- const iframe = document.createElement('iframe');
- document.body.appendChild(iframe);
- iframe.onload = fulfill;
- iframe.src = src;
- return promise;
- }""",
- server.CROSS_PROCESS_PREFIX + "/grid.html",
- )
- document_cookie = await page.frames[1].evaluate(
- """() => {
- document.cookie = 'username=John Doe';
- return document.cookie;
- }"""
- )
-
- await page.wait_for_timeout(2000)
- 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")
- 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()
-
-
-async def test_should_not_override_viewport_size_when_passed_null(
- browser_type: BrowserType, launch_arguments: Dict, server: Server
-) -> None:
- # Our WebKit embedder does not respect window features.
- browser = await browser_type.launch(**{**launch_arguments, "headless": False})
- context = await browser.new_context(no_viewport=True)
- page = await context.new_page()
- await page.goto(server.EMPTY_PAGE)
- async with page.expect_popup() as popup_info:
- await page.evaluate(
- """() => {
- const win = window.open(window.location.href, 'Title', 'toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=600,height=300,top=0,left=0');
- win.resizeTo(500, 450);
- }"""
- )
- popup = await popup_info.value
- await popup.wait_for_load_state()
- await popup.wait_for_function(
- """() => window.outerWidth === 500 && window.outerHeight === 450"""
- )
- await context.close()
- await browser.close()
-
-
-async def test_page_bring_to_front_should_work(
- browser_type: BrowserType, launch_arguments: Dict
-) -> None:
- browser = await browser_type.launch(**{**launch_arguments, "headless": False})
- page1 = await browser.new_page()
- await page1.set_content("Page1")
- page2 = await browser.new_page()
- await page2.set_content("Page2")
-
- await page1.bring_to_front()
- assert await page1.evaluate("document.visibilityState") == "visible"
- assert await page2.evaluate("document.visibilityState") == "visible"
-
- await page2.bring_to_front()
- assert await page1.evaluate("document.visibilityState") == "visible"
- assert await page2.evaluate("document.visibilityState") == "visible"
- await browser.close()
diff --git a/tests/async/test_ignore_https_errors.py b/tests/async/test_ignore_https_errors.py
deleted file mode 100644
index f583fec..0000000
--- a/tests/async/test_ignore_https_errors.py
+++ /dev/null
@@ -1,37 +0,0 @@
-# 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 pytest
-
-from playwright.async_api import Browser, Error
-from tests.server import Server
-
-
-async def test_ignore_https_error_should_work(browser: Browser, https_server: Server) -> None:
- context = await browser.new_context(ignore_https_errors=True)
- page = await context.new_page()
- response = await page.goto(https_server.EMPTY_PAGE)
- assert response
- assert response.ok
- await context.close()
-
-
-async def test_ignore_https_error_should_work_negative_case(
- browser: Browser, https_server: Server
-) -> None:
- context = await browser.new_context()
- page = await context.new_page()
- with pytest.raises(Error):
- await page.goto(https_server.EMPTY_PAGE)
- await context.close()
diff --git a/tests/async/test_input.py b/tests/async/test_input.py
deleted file mode 100644
index b4a371a..0000000
--- a/tests/async/test_input.py
+++ /dev/null
@@ -1,500 +0,0 @@
-# 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 os
-import re
-import shutil
-import sys
-from pathlib import Path
-from typing import Any
-
-import pytest
-from flaky import flaky
-from playwright._impl._path_utils import get_file_dirname
-from playwright.async_api import Error, FilePayload, Page
-
-from tests.server import Server
-from tests.utils import chromium_version_less_than, must
-
-_dirname = get_file_dirname()
-FILE_TO_UPLOAD = _dirname / ".." / "assets/file-to-upload.txt"
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_should_upload_the_file(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/fileupload.html")
- file_path = os.path.relpath(FILE_TO_UPLOAD, os.getcwd())
- input = await page.query_selector("input")
- assert input
- await input.set_input_files(file_path)
- assert await page.evaluate("e => e.files[0].name", input) == "file-to-upload.txt"
- assert (
- await page.evaluate(
- """e => {
- reader = new FileReader()
- promise = new Promise(fulfill => reader.onload = fulfill)
- reader.readAsText(e.files[0])
- return promise.then(() => reader.result)
- }""",
- input,
- )
- == "contents of the file\n"
- )
-
-
-async def test_should_work(page: Page, assetdir: Path) -> None:
- await page.set_content(" ")
- await page.set_input_files("input", assetdir / "file-to-upload.txt")
- assert await page.eval_on_selector("input", "input => input.files.length") == 1
- assert (
- await page.eval_on_selector("input", "input => input.files[0].name") == "file-to-upload.txt"
- )
-
-
-async def test_should_set_from_memory(page: Page) -> None:
- await page.set_content(" ")
- file: FilePayload = {
- "name": "test.txt",
- "mimeType": "text/plain",
- "buffer": b"this is a test",
- }
- await page.set_input_files(
- "input",
- files=[file],
- )
- assert await page.eval_on_selector("input", "input => input.files.length") == 1
- assert await page.eval_on_selector("input", "input => input.files[0].name") == "test.txt"
-
-
-async def test_should_emit_event(page: Page) -> None:
- await page.set_content(" ")
- fc_done: asyncio.Future = asyncio.Future()
- page.once("filechooser", lambda file_chooser: fc_done.set_result(file_chooser))
- await page.click("input")
- file_chooser = await fc_done
- assert file_chooser
- assert (
- repr(file_chooser)
- == f""
- )
-
-
-async def test_should_work_when_file_input_is_attached_to_dom(page: Page) -> None:
- await page.set_content(" ")
- async with page.expect_file_chooser() as fc_info:
- await page.click("input")
- file_chooser = await fc_info.value
- assert file_chooser
-
-
-async def test_should_work_when_file_input_is_not_attached_to_DOM(page: Page) -> None:
- async with page.expect_file_chooser() as fc_info:
- await page.evaluate(
- """() => {
- el = document.createElement('input')
- el.type = 'file'
- el.click()
- }"""
- )
- file_chooser = await fc_info.value
- assert file_chooser
-
-
-async def test_should_return_the_same_file_chooser_when_there_are_many_watchdogs_simultaneously(
- page: Page,
-) -> None:
- await page.set_content(" ")
- results = await asyncio.gather(
- page.wait_for_event("filechooser"),
- page.wait_for_event("filechooser"),
- page.eval_on_selector("input", "input => input.click()"),
- )
- assert results[0] == results[1]
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_should_accept_single_file(page: Page) -> None:
- await page.set_content(' ')
- async with page.expect_file_chooser() as fc_info:
- await page.click("input")
- file_chooser = await fc_info.value
- assert file_chooser.page == page
- assert file_chooser.element
- await file_chooser.set_files(FILE_TO_UPLOAD)
- assert await page.eval_on_selector("input", "input => input.files.length") == 1
- assert (
- await page.eval_on_selector("input", "input => input.files[0].name") == "file-to-upload.txt"
- )
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_should_be_able_to_read_selected_file(page: Page) -> None:
- page.once("filechooser", lambda file_chooser: file_chooser.set_files(FILE_TO_UPLOAD))
- await page.set_content(" ")
- content = await page.eval_on_selector(
- "input",
- """async picker => {
- picker.click();
- await new Promise(x => picker.oninput = x);
- const reader = new FileReader();
- const promise = new Promise(fulfill => reader.onload = fulfill);
- reader.readAsText(picker.files[0]);
- return promise.then(() => reader.result);
- }""",
- )
- assert content == "contents of the file\n"
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_should_be_able_to_reset_selected_files_with_empty_file_list(
- page: Page,
-) -> None:
- await page.set_content(" ")
- page.once("filechooser", lambda file_chooser: file_chooser.set_files(FILE_TO_UPLOAD))
- file_length = 0
- async with page.expect_file_chooser():
- file_length = await page.eval_on_selector(
- "input",
- """async picker => {
- picker.click();
- await new Promise(x => picker.oninput = x);
- return picker.files.length;
- }""",
- )
- assert file_length == 1
-
- page.once("filechooser", lambda file_chooser: file_chooser.set_files([]))
- async with page.expect_file_chooser():
- file_length = await page.eval_on_selector(
- "input",
- """async picker => {
- picker.click();
- await new Promise(x => picker.oninput = x);
- return picker.files.length;
- }""",
- )
- assert file_length == 0
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_should_not_accept_multiple_files_for_single_file_input(
- page: Page, assetdir: Path
-) -> None:
- await page.set_content(" ")
- async with page.expect_file_chooser() as fc_info:
- await page.click("input")
- file_chooser = await fc_info.value
- with pytest.raises(Exception) as exc_info:
- await file_chooser.set_files(
- [
- os.path.realpath(assetdir / "file-to-upload.txt"),
- os.path.realpath(assetdir / "pptr.png"),
- ]
- )
- assert exc_info.value
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_should_emit_input_and_change_events(page: Page) -> None:
- events = []
- await page.expose_function("eventHandled", lambda e: events.append(e))
- await page.set_content(
- """
-
-
- """
- )
- await must(await page.query_selector("input")).set_input_files(FILE_TO_UPLOAD)
- assert len(events) == 2
- assert events[0]["type"] == "input"
- assert events[1]["type"] == "change"
-
-
-async def test_should_work_for_single_file_pick(page: Page) -> None:
- await page.set_content(" ")
- async with page.expect_file_chooser() as fc_info:
- await page.click("input")
- file_chooser = await fc_info.value
- assert file_chooser.is_multiple() is False
-
-
-async def test_should_work_for_multiple(page: Page) -> None:
- await page.set_content(" ")
- async with page.expect_file_chooser() as fc_info:
- await page.click("input")
- file_chooser = await fc_info.value
- assert file_chooser.is_multiple()
-
-
-async def test_should_work_for_webkitdirectory(page: Page) -> None:
- await page.set_content(" ")
- async with page.expect_file_chooser() as fc_info:
- await page.click("input")
- file_chooser = await fc_info.value
- assert file_chooser.is_multiple()
-
-
-def _assert_wheel_event(expected: Any, received: Any, browser_name: str) -> None:
- # Chromium reports deltaX/deltaY scaled by host device scale factor.
- # https://bugs.chromium.org/p/chromium/issues/detail?id=1324819
- # https://github.com/microsoft/playwright/issues/7362
- # Different bots have different scale factors (usually 1 or 2), so we just ignore the values
- # instead of guessing the host scale factor.
- if sys.platform == "darwin" and browser_name == "chromium":
- del expected["deltaX"]
- del expected["deltaY"]
- del received["deltaX"]
- del received["deltaY"]
- assert received == expected
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_wheel_should_work(page: Page, browser_name: str) -> None:
- await page.set_content(
- """
-
- """
- )
- await page.mouse.move(50, 60)
- await _listen_for_wheel_events(page, "div")
- await page.mouse.wheel(0, 100)
- _assert_wheel_event(
- await page.evaluate("window.lastEvent"),
- {
- "deltaX": 0,
- "deltaY": 100,
- "clientX": 50,
- "clientY": 60,
- "deltaMode": 0,
- "ctrlKey": False,
- "shiftKey": False,
- "altKey": False,
- "metaKey": False,
- },
- browser_name,
- )
- await page.wait_for_function("window.scrollY === 100")
-
-
-async def _listen_for_wheel_events(page: Page, selector: str) -> None:
- await page.evaluate(
- """
- selector => {
- document.querySelector(selector).addEventListener('wheel', (e) => {
- window['lastEvent'] = {
- deltaX: e.deltaX,
- deltaY: e.deltaY,
- clientX: e.clientX,
- clientY: e.clientY,
- deltaMode: e.deltaMode,
- ctrlKey: e.ctrlKey,
- shiftKey: e.shiftKey,
- altKey: e.altKey,
- metaKey: e.metaKey,
- };
- }, { passive: false });
- }
- """,
- selector,
- )
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-@flaky
-async def test_should_upload_large_file(page: Page, server: Server, tmp_path: Path) -> None:
- await page.goto(server.PREFIX + "/input/fileupload.html")
- large_file_path = tmp_path / "200MB.zip"
- data = b"A" * 1024
- with large_file_path.open("wb") as f:
- for i in range(0, 200 * 1024 * 1024, len(data)):
- f.write(data)
- input = page.locator('input[type="file"]')
- events = await input.evaluate_handle(
- """
- e => {
- const events = [];
- e.addEventListener('input', () => events.push('input'));
- e.addEventListener('change', () => events.push('change'));
- return events;
- }
- """
- )
-
- await input.set_input_files(large_file_path)
- assert await input.evaluate("e => e.files[0].name") == "200MB.zip"
- assert await events.evaluate("e => e") == ["input", "change"]
-
- [request, _] = await asyncio.gather(
- server.wait_for_request("/upload"),
- page.click("input[type=submit]"),
- )
-
- contents = request.args[b"file1"][0]
- assert len(contents) == 200 * 1024 * 1024
- assert contents[:1024] == data
- # flake8: noqa: E203
- assert contents[len(contents) - 1024 :] == data
- assert request.post_body
- match = re.search(
- rb'^.*Content-Disposition: form-data; name="(?P.*)"; filename="(?P.*)".*$',
- request.post_body,
- re.MULTILINE,
- )
- assert match
- assert match.group("name") == b"file1"
- assert match.group("filename") == b"200MB.zip"
-
-
-async def test_set_input_files_should_preserve_last_modified_timestamp(
- page: Page,
- assetdir: Path,
-) -> None:
- await page.set_content(" ")
- input = page.locator("input")
- files = ["file-to-upload.txt", "file-to-upload-2.txt"]
- await input.set_input_files([assetdir / file for file in files])
- assert await input.evaluate("input => [...input.files].map(f => f.name)") == files
- timestamps = await input.evaluate("input => [...input.files].map(f => f.lastModified)")
- expected_timestamps = [os.path.getmtime(assetdir / file) * 1000 for file in files]
-
- # On Linux browser sometimes reduces the timestamp by 1ms: 1696272058110.0715 -> 1696272058109 or even
- # rounds it to seconds in WebKit: 1696272058110 -> 1696272058000.
- for i in range(len(timestamps)):
- assert abs(timestamps[i] - expected_timestamps[i]) < 1000
-
-
-@flaky
-async def test_should_upload_multiple_large_file(
- page: Page, server: Server, tmp_path: Path
-) -> None:
- files_count = 10
- await page.goto(server.PREFIX + "/input/fileupload-multi.html")
- upload_file = tmp_path / "50MB_1.zip"
- data = b"A" * 1024
- with upload_file.open("wb") as f:
- # 49 is close to the actual limit
- for i in range(0, 49 * 1024):
- f.write(data)
- input = page.locator('input[type="file"]')
- upload_files = [upload_file]
- for i in range(2, files_count + 1):
- dst_file = tmp_path / f"50MB_{i}.zip"
- shutil.copy(upload_file, dst_file)
- upload_files.append(dst_file)
- async with page.expect_file_chooser() as fc_info:
- await input.click()
- file_chooser = await fc_info.value
- await file_chooser.set_files(upload_files)
- files_len = await page.evaluate('document.getElementsByTagName("input")[0].files.length')
- assert file_chooser.is_multiple()
- assert files_len == files_count
- for path in upload_files:
- path.unlink()
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_should_upload_a_folder(
- page: Page,
- server: Server,
- tmp_path: Path,
- browser_name: str,
- browser_version: str,
- headless: bool,
-) -> None:
- await page.goto(server.PREFIX + "/input/folderupload.html")
- input = await page.query_selector("input")
- assert input
- dir = tmp_path / "file-upload-test"
- dir.mkdir()
- (dir / "file1.txt").write_text("file1 content")
- (dir / "file2").write_text("file2 content")
- (dir / "sub-dir").mkdir()
- (dir / "sub-dir" / "really.txt").write_text("sub-dir file content")
- await input.set_input_files(dir)
- assert set(await input.evaluate("e => [...e.files].map(f => f.webkitRelativePath)")) == set(
- [
- "file-upload-test/file1.txt",
- "file-upload-test/file2",
- # https://issues.chromium.org/issues/345393164
- *(
- []
- if browser_name == "chromium"
- and headless
- and chromium_version_less_than(browser_version, "127.0.6533.0")
- else ["file-upload-test/sub-dir/really.txt"]
- ),
- ]
- )
- webkit_relative_paths = await input.evaluate("e => [...e.files].map(f => f.webkitRelativePath)")
- for i, webkit_relative_path in enumerate(webkit_relative_paths):
- content = await input.evaluate(
- """(e, i) => {
- const reader = new FileReader();
- const promise = new Promise(fulfill => reader.onload = fulfill);
- reader.readAsText(e.files[i]);
- return promise.then(() => reader.result);
- }""",
- i,
- )
- assert content == (dir / ".." / webkit_relative_path).read_text()
-
-
-async def test_should_upload_a_folder_and_throw_for_multiple_directories(
- page: Page, server: Server, tmp_path: Path
-) -> None:
- await page.goto(server.PREFIX + "/input/folderupload.html")
- input = page.locator("input")
- dir = tmp_path / "file-upload-test"
- dir.mkdir()
- (dir / "folder1").mkdir()
- (dir / "folder1" / "file1.txt").write_text("file1 content")
- (dir / "folder2").mkdir()
- (dir / "folder2" / "file2.txt").write_text("file2 content")
- with pytest.raises(Error) as exc_info:
- await input.set_input_files([dir / "folder1", dir / "folder2"])
- assert "Multiple directories are not supported" in exc_info.value.message
-
-
-async def test_should_throw_if_a_directory_and_files_are_passed(
- page: Page, server: Server, tmp_path: Path
-) -> None:
- await page.goto(server.PREFIX + "/input/folderupload.html")
- input = page.locator("input")
- dir = tmp_path / "file-upload-test"
- dir.mkdir()
- (dir / "file1.txt").write_text("file1 content")
- with pytest.raises(Error) as exc_info:
- await input.set_input_files([dir, dir / "file1.txt"])
- assert "File paths must be all files or a single directory" in exc_info.value.message
-
-
-async def test_should_throw_when_upload_a_folder_in_a_normal_file_upload_input(
- page: Page, server: Server, tmp_path: Path
-) -> None:
- await page.goto(server.PREFIX + "/input/fileupload.html")
- input = await page.query_selector("input")
- assert input
- dir = tmp_path / "file-upload-test"
- dir.mkdir()
- (dir / "file1.txt").write_text("file1 content")
- with pytest.raises(Error) as exc_info:
- await input.set_input_files(dir)
- assert (
- "File input does not support directories, pass individual files instead"
- in exc_info.value.message
- )
diff --git a/tests/async/test_issues.py b/tests/async/test_issues.py
deleted file mode 100644
index 5b63b02..0000000
--- a/tests/async/test_issues.py
+++ /dev/null
@@ -1,53 +0,0 @@
-# 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.
-
-from asyncio import FIRST_COMPLETED, CancelledError, create_task, wait
-from typing import Dict
-
-import pytest
-
-from playwright.async_api import Browser, BrowserType, Page, Playwright
-
-
-@pytest.mark.only_browser("chromium")
-async def test_issue_189(browser_type: BrowserType, launch_arguments: Dict) -> None:
- browser = await browser_type.launch(**launch_arguments, ignore_default_args=["--mute-audio"])
- page = await browser.new_page()
- assert await page.evaluate("1 + 1") == 2
- await browser.close()
-
-
-@pytest.mark.only_browser("chromium")
-async def test_issue_195(playwright: Playwright, browser: Browser) -> None:
- iphone_11 = playwright.devices["iPhone 11"]
- context = await browser.new_context(**iphone_11)
- await context.close()
-
-
-async def test_connection_task_cancel(page: Page) -> None:
- await page.set_content(" ")
- done, pending = await wait(
- {
- create_task(page.wait_for_selector("input")),
- create_task(page.wait_for_selector("#will-never-resolve")),
- },
- return_when=FIRST_COMPLETED,
- )
- assert len(done) == 1
- assert len(pending) == 1
- for task in pending:
- task.cancel()
- with pytest.raises(CancelledError):
- await task
- assert list(pending)[0].cancelled()
diff --git a/tests/async/test_jshandle.py b/tests/async/test_jshandle.py
deleted file mode 100644
index 8181a54..0000000
--- a/tests/async/test_jshandle.py
+++ /dev/null
@@ -1,231 +0,0 @@
-# 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 json
-import math
-from datetime import datetime, timezone
-from typing import Any, Dict
-
-import pytest
-from playwright.async_api import Page
-
-
-async def test_jshandle_evaluate_work(page: Page) -> None:
- window_handle = await page.evaluate_handle("window")
- assert window_handle
- assert repr(window_handle) == f""
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_jshandle_evaluate_accept_object_handle_as_argument(page: Page) -> None:
- navigator_handle = await page.evaluate_handle("navigator")
- text = await page.evaluate("e => e.userAgent", navigator_handle)
- assert "Mozilla" in text
-
-
-async def test_jshandle_evaluate_accept_handle_to_primitive_types(page: Page) -> None:
- handle = await page.evaluate_handle("5")
- is_five = await page.evaluate("e => Object.is(e, 5)", handle)
- assert is_five
-
-
-async def test_jshandle_evaluate_accept_nested_handle(page: Page) -> None:
- foo = await page.evaluate_handle('({ x: 1, y: "foo" })')
- result = await page.evaluate("({ foo }) => foo", {"foo": foo})
- assert result == {"x": 1, "y": "foo"}
-
-
-async def test_jshandle_evaluate_accept_nested_window_handle(page: Page) -> None:
- foo = await page.evaluate_handle("window")
- result = await page.evaluate("({ foo }) => foo === window", {"foo": foo})
- assert result
-
-
-async def test_jshandle_evaluate_accept_multiple_nested_handles(page: Page) -> None:
- foo = await page.evaluate_handle('({ x: 1, y: "foo" })')
- bar = await page.evaluate_handle("5")
- baz = await page.evaluate_handle('["baz"]')
- result = await page.evaluate(
- "x => JSON.stringify(x)",
- {"a1": {"foo": foo}, "a2": {"bar": bar, "arr": [{"baz": baz}]}},
- )
- assert json.loads(result) == {
- "a1": {"foo": {"x": 1, "y": "foo"}},
- "a2": {"bar": 5, "arr": [{"baz": ["baz"]}]},
- }
-
-
-async def test_jshandle_evaluate_should_work_for_circular_objects(page: Page) -> None:
- a: Dict[str, Any] = {"x": 1}
- a["y"] = a
- result = await page.evaluate("a => { a.y.x += 1; return a; }", a)
- assert result["x"] == 2
- assert result["y"]["x"] == 2
- assert result == result["y"]
-
-
-async def test_jshandle_evaluate_accept_same_nested_object_multiple_times(
- page: Page,
-) -> None:
- foo = {"x": 1}
- assert await page.evaluate("x => x", {"foo": foo, "bar": [foo], "baz": {"foo": foo}}) == {
- "foo": {"x": 1},
- "bar": [{"x": 1}],
- "baz": {"foo": {"x": 1}},
- }
-
-
-async def test_jshandle_evaluate_accept_object_handle_to_unserializable_value(
- page: Page,
-) -> None:
- handle = await page.evaluate_handle("() => Infinity")
- assert await page.evaluate("e => Object.is(e, Infinity)", handle)
-
-
-async def test_jshandle_evaluate_pass_configurable_args(page: Page) -> None:
- result = await page.evaluate(
- """arg => {
- if (arg.foo !== 42)
- throw new Error('Not a 42');
- arg.foo = 17;
- if (arg.foo !== 17)
- throw new Error('Not 17');
- delete arg.foo;
- if (arg.foo === 17)
- throw new Error('Still 17');
- return arg;
- }""",
- {"foo": 42},
- )
- assert result == {}
-
-
-async def test_jshandle_properties_get_property(page: Page) -> None:
- handle1 = await page.evaluate_handle(
- """() => ({
- one: 1,
- two: 2,
- three: 3
- })"""
- )
- handle2 = await handle1.get_property("two")
- assert await handle2.json_value() == 2
-
-
-async def test_jshandle_properties_work_with_undefined_null_and_empty(
- page: Page,
-) -> None:
- handle = await page.evaluate_handle(
- """() => ({
- undefined: undefined,
- null: null,
- })"""
- )
- undefined_handle = await handle.get_property("undefined")
- assert await undefined_handle.json_value() is None
- null_handle = await handle.get_property("null")
- assert await null_handle.json_value() is None
- empty_handle = await handle.get_property("empty")
- assert await empty_handle.json_value() is None
-
-
-async def test_jshandle_properties_work_with_unserializable_values(page: Page) -> None:
- handle = await page.evaluate_handle(
- """() => ({
- infinity: Infinity,
- negInfinity: -Infinity,
- nan: NaN,
- negZero: -0
- })"""
- )
- infinity_handle = await handle.get_property("infinity")
- assert await infinity_handle.json_value() == float("inf")
- neg_infinity_handle = await handle.get_property("negInfinity")
- assert await neg_infinity_handle.json_value() == float("-inf")
- nan_handle = await handle.get_property("nan")
- assert math.isnan(await nan_handle.json_value()) is True
- neg_zero_handle = await handle.get_property("negZero")
- assert await neg_zero_handle.json_value() == float("-0")
-
-
-async def test_jshandle_properties_get_properties(page: Page) -> None:
- handle = await page.evaluate_handle('() => ({ foo: "bar" })')
- properties = await handle.get_properties()
- assert "foo" in properties
- foo = properties["foo"]
- assert await foo.json_value() == "bar"
-
-
-async def test_jshandle_properties_return_empty_map_for_non_objects(page: Page) -> None:
- handle = await page.evaluate_handle("123")
- properties = await handle.get_properties()
- assert properties == {}
-
-
-async def test_jshandle_json_value_work(page: Page) -> None:
- handle = await page.evaluate_handle('() => ({foo: "bar"})')
- json = await handle.json_value()
- assert json == {"foo": "bar"}
-
-
-async def test_jshandle_json_value_work_with_dates(page: Page) -> None:
- handle = await page.evaluate_handle('() => new Date("2020-05-27T01:31:38.506Z")')
- json = await handle.json_value()
- assert json == datetime.fromisoformat("2020-05-27T01:31:38.506").replace(tzinfo=timezone.utc)
-
-
-async def test_jshandle_json_value_should_work_for_circular_object(page: Page) -> None:
- handle = await page.evaluate_handle("const a = {}; a.b = a; a")
- a: Dict[str, Any] = {}
- a["b"] = a
- result = await handle.json_value()
- # Node test looks like the below, but assert isn't smart enough to handle this:
- # assert await handle.json_value() == a
- assert result["b"] == result
-
-
-async def test_jshandle_as_element_work(page: Page) -> None:
- handle = await page.evaluate_handle("document.body")
- element = handle.as_element()
- assert element is not None
-
-
-async def test_jshandle_as_element_return_none_for_non_elements(page: Page) -> None:
- handle = await page.evaluate_handle("2")
- element = handle.as_element()
- assert element is None
-
-
-async def test_jshandle_to_string_work_for_primitives(page: Page) -> None:
- number_handle = await page.evaluate_handle("2")
- assert str(number_handle) == "2"
- string_handle = await page.evaluate_handle('"a"')
- assert str(string_handle) == "a"
-
-
-async def test_jshandle_to_string_work_for_complicated_objects(
- page: Page, browser_name: str
-) -> None:
- handle = await page.evaluate_handle("window")
- if browser_name != "firefox":
- assert str(handle) == "Window"
- else:
- assert str(handle) == "JSHandle@object"
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_jshandle_to_string_work_for_promises(page: Page) -> None:
- handle = await page.evaluate_handle("({b: Promise.resolve(123)})")
- b_handle = await handle.get_property("b")
- assert str(b_handle) == "Promise"
diff --git a/tests/async/test_keyboard.py b/tests/async/test_keyboard.py
deleted file mode 100644
index 7ba5e75..0000000
--- a/tests/async/test_keyboard.py
+++ /dev/null
@@ -1,525 +0,0 @@
-# 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 pytest
-from playwright.async_api import Error, JSHandle, Page
-
-from tests.server import Server
-
-from .utils import Utils
-
-
-async def captureLastKeydown(page: Page) -> JSHandle:
- lastEvent = await page.evaluate_handle(
- """() => {
- const lastEvent = {
- repeat: false,
- location: -1,
- code: '',
- key: '',
- metaKey: false,
- keyIdentifier: 'unsupported'
- };
- document.addEventListener('keydown', e => {
- lastEvent.repeat = e.repeat;
- lastEvent.location = e.location;
- lastEvent.key = e.key;
- lastEvent.code = e.code;
- lastEvent.metaKey = e.metaKey;
- // keyIdentifier only exists in WebKit, and isn't in TypeScript's lib.
- lastEvent.keyIdentifier = 'keyIdentifier' in e && e.keyIdentifier;
- }, true);
- return lastEvent;
- }"""
- )
- return lastEvent
-
-
-async def test_keyboard_type_into_a_textarea(page: Page) -> None:
- await page.evaluate(
- """
- const textarea = document.createElement('textarea');
- document.body.appendChild(textarea);
- textarea.focus();
- """
- )
- text = "Hello world. I am the text that was typed!"
- await page.keyboard.type(text)
- assert await page.evaluate('document.querySelector("textarea").value') == text
-
-
-async def test_keyboard_move_with_the_arrow_keys(page: Page, server: Server) -> None:
- await page.goto(f"{server.PREFIX}/input/textarea.html")
- await page.type("textarea", "Hello World!")
- assert await page.evaluate("document.querySelector('textarea').value") == "Hello World!"
- for _ in "World!":
- await page.keyboard.press("ArrowLeft")
- await page.keyboard.type("inserted ")
- assert (
- await page.evaluate("document.querySelector('textarea').value") == "Hello inserted World!"
- )
- await page.keyboard.down("Shift")
- for _ in "inserted ":
- await page.keyboard.press("ArrowLeft")
- await page.keyboard.up("Shift")
- await page.keyboard.press("Backspace")
- assert await page.evaluate("document.querySelector('textarea').value") == "Hello World!"
-
-
-async def test_keyboard_send_a_character_with_elementhandle_press(
- page: Page, server: Server
-) -> None:
- await page.goto(f"{server.PREFIX}/input/textarea.html")
- textarea = await page.query_selector("textarea")
- assert textarea
- await textarea.press("a")
- assert await page.evaluate("document.querySelector('textarea').value") == "a"
- await page.evaluate("() => window.addEventListener('keydown', e => e.preventDefault(), true)")
- await textarea.press("b")
- assert await page.evaluate("document.querySelector('textarea').value") == "a"
-
-
-async def test_should_send_a_character_with_send_character(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/textarea.html")
- await page.focus("textarea")
- await page.keyboard.insert_text("嗨")
- assert await page.evaluate('() => document.querySelector("textarea").value') == "嗨"
- await page.evaluate('() => window.addEventListener("keydown", e => e.preventDefault(), true)')
- await page.keyboard.insert_text("a")
- assert await page.evaluate('() => document.querySelector("textarea").value') == "嗨a"
-
-
-async def test_should_only_emit_input_event(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/textarea.html")
- await page.focus("textarea")
- events = await page.evaluate_handle(
- """() => {
- const events = [];
- document.addEventListener('keydown', e => events.push(e.type));
- document.addEventListener('keyup', e => events.push(e.type));
- document.addEventListener('keypress', e => events.push(e.type));
- document.addEventListener('input', e => events.push(e.type));
- return events;
- }"""
- )
-
- await page.keyboard.insert_text("hello world")
- assert await events.json_value() == ["input"]
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_should_report_shiftkey(
- page: Page, server: Server, is_mac: bool, is_firefox: bool
-) -> None:
- if is_firefox and is_mac:
- pytest.skip()
- await page.goto(server.PREFIX + "/input/keyboard.html")
- keyboard = page.keyboard
- codeForKey = {"Shift": 16, "Alt": 18, "Control": 17}
- for modifierKey in codeForKey.keys():
- await keyboard.down(modifierKey)
- assert (
- await page.evaluate("() => getResult()")
- == "Keydown: "
- + modifierKey
- + " "
- + modifierKey
- + "Left "
- + str(codeForKey[modifierKey])
- + " ["
- + modifierKey
- + "]"
- )
- await keyboard.down("!")
- # Shift+! will generate a keypress
- if modifierKey == "Shift":
- assert (
- await page.evaluate("() => getResult()")
- == "Keydown: ! Digit1 49 ["
- + modifierKey
- + "]\nKeypress: ! Digit1 33 33 ["
- + modifierKey
- + "]"
- )
- else:
- assert (
- await page.evaluate("() => getResult()")
- == "Keydown: ! Digit1 49 [" + modifierKey + "]"
- )
-
- await keyboard.up("!")
- assert (
- await page.evaluate("() => getResult()") == "Keyup: ! Digit1 49 [" + modifierKey + "]"
- )
- await keyboard.up(modifierKey)
- assert (
- await page.evaluate("() => getResult()")
- == "Keyup: "
- + modifierKey
- + " "
- + modifierKey
- + "Left "
- + str(codeForKey[modifierKey])
- + " []"
- )
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_should_report_multiple_modifiers(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/keyboard.html")
- keyboard = page.keyboard
- await keyboard.down("Control")
- assert await page.evaluate("() => getResult()") == "Keydown: Control ControlLeft 17 [Control]"
- await keyboard.down("Alt")
- assert await page.evaluate("() => getResult()") == "Keydown: Alt AltLeft 18 [Alt Control]"
- await keyboard.down(";")
- assert await page.evaluate("() => getResult()") == "Keydown: ; Semicolon 186 [Alt Control]"
- await keyboard.up(";")
- assert await page.evaluate("() => getResult()") == "Keyup: ; Semicolon 186 [Alt Control]"
- await keyboard.up("Control")
- assert await page.evaluate("() => getResult()") == "Keyup: Control ControlLeft 17 [Alt]"
- await keyboard.up("Alt")
- assert await page.evaluate("() => getResult()") == "Keyup: Alt AltLeft 18 []"
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_should_send_proper_codes_while_typing(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/keyboard.html")
- await page.keyboard.type("!")
- assert await page.evaluate("() => getResult()") == "\n".join(
- [
- "Keydown: ! Digit1 49 []",
- "Keypress: ! Digit1 33 33 []",
- "Keyup: ! Digit1 49 []",
- ]
- )
- await page.keyboard.type("^")
- assert await page.evaluate("() => getResult()") == "\n".join(
- [
- "Keydown: ^ Digit6 54 []",
- "Keypress: ^ Digit6 94 94 []",
- "Keyup: ^ Digit6 54 []",
- ]
- )
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_should_send_proper_codes_while_typing_with_shift(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/keyboard.html")
- keyboard = page.keyboard
- await keyboard.down("Shift")
- await page.keyboard.type("~")
- assert await page.evaluate("() => getResult()") == "\n".join(
- [
- "Keydown: Shift ShiftLeft 16 [Shift]",
- "Keydown: ~ Backquote 192 [Shift]", # 192 is ` keyCode
- "Keypress: ~ Backquote 126 126 [Shift]", # 126 is ~ charCode
- "Keyup: ~ Backquote 192 [Shift]",
- ]
- )
- await keyboard.up("Shift")
-
-
-async def test_should_not_type_canceled_events(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/textarea.html")
- await page.focus("textarea")
- await page.evaluate(
- """() => {
- window.addEventListener('keydown', event => {
- event.stopPropagation();
- event.stopImmediatePropagation();
- if (event.key === 'l')
- event.preventDefault();
- if (event.key === 'o')
- event.preventDefault();
- }, false);
- }"""
- )
-
- await page.keyboard.type("Hello World!")
- assert await page.eval_on_selector("textarea", "textarea => textarea.value") == "He Wrd!"
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_should_press_plus(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/keyboard.html")
- await page.keyboard.press("+")
- assert await page.evaluate("() => getResult()") == "\n".join(
- [
- "Keydown: + Equal 187 []", # 192 is ` keyCode
- "Keypress: + Equal 43 43 []", # 126 is ~ charCode
- "Keyup: + Equal 187 []",
- ]
- )
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_should_press_shift_plus(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/keyboard.html")
- await page.keyboard.press("Shift++")
- assert await page.evaluate("() => getResult()") == "\n".join(
- [
- "Keydown: Shift ShiftLeft 16 [Shift]",
- "Keydown: + Equal 187 [Shift]", # 192 is ` keyCode
- "Keypress: + Equal 43 43 [Shift]", # 126 is ~ charCode
- "Keyup: + Equal 187 [Shift]",
- "Keyup: Shift ShiftLeft 16 []",
- ]
- )
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_should_support_plus_separated_modifiers(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/keyboard.html")
- await page.keyboard.press("Shift+~")
- assert await page.evaluate("() => getResult()") == "\n".join(
- [
- "Keydown: Shift ShiftLeft 16 [Shift]",
- "Keydown: ~ Backquote 192 [Shift]", # 192 is ` keyCode
- "Keypress: ~ Backquote 126 126 [Shift]", # 126 is ~ charCode
- "Keyup: ~ Backquote 192 [Shift]",
- "Keyup: Shift ShiftLeft 16 []",
- ]
- )
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_should_suport_multiple_plus_separated_modifiers(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/keyboard.html")
- await page.keyboard.press("Control+Shift+~")
- assert await page.evaluate("() => getResult()") == "\n".join(
- [
- "Keydown: Control ControlLeft 17 [Control]",
- "Keydown: Shift ShiftLeft 16 [Control Shift]",
- "Keydown: ~ Backquote 192 [Control Shift]", # 192 is ` keyCode
- "Keyup: ~ Backquote 192 [Control Shift]",
- "Keyup: Shift ShiftLeft 16 [Control]",
- "Keyup: Control ControlLeft 17 []",
- ]
- )
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_should_shift_raw_codes(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/keyboard.html")
- await page.keyboard.press("Shift+Digit3")
- assert await page.evaluate("() => getResult()") == "\n".join(
- [
- "Keydown: Shift ShiftLeft 16 [Shift]",
- "Keydown: # Digit3 51 [Shift]", # 51 is # keyCode
- "Keypress: # Digit3 35 35 [Shift]", # 35 is # charCode
- "Keyup: # Digit3 51 [Shift]",
- "Keyup: Shift ShiftLeft 16 []",
- ]
- )
-
-
-async def test_should_specify_repeat_property(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/textarea.html")
- await page.focus("textarea")
- lastEvent = await captureLastKeydown(page)
- await page.keyboard.down("a")
- assert await lastEvent.evaluate("e => e.repeat") is False
- await page.keyboard.press("a")
- assert await lastEvent.evaluate("e => e.repeat")
-
- await page.keyboard.down("b")
- assert await lastEvent.evaluate("e => e.repeat") is False
- await page.keyboard.down("b")
- assert await lastEvent.evaluate("e => e.repeat")
-
- await page.keyboard.up("a")
- await page.keyboard.down("a")
- assert await lastEvent.evaluate("e => e.repeat") is False
-
-
-async def test_should_type_all_kinds_of_characters(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/textarea.html")
- await page.focus("textarea")
- text = "This text goes onto two lines.\nThis character is 嗨."
- await page.keyboard.type(text)
- assert await page.eval_on_selector("textarea", "t => t.value") == text
-
-
-async def test_should_specify_location(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/textarea.html")
- lastEvent = await captureLastKeydown(page)
- textarea = await page.query_selector("textarea")
- assert textarea
-
- await textarea.press("Digit5")
- assert await lastEvent.evaluate("e => e.location") == 0
-
- await textarea.press("ControlLeft")
- assert await lastEvent.evaluate("e => e.location") == 1
-
- await textarea.press("ControlRight")
- assert await lastEvent.evaluate("e => e.location") == 2
-
- await textarea.press("NumpadSubtract")
- assert await lastEvent.evaluate("e => e.location") == 3
-
-
-async def test_should_press_enter(page: Page) -> None:
- await page.set_content("")
- await page.focus("textarea")
- lastEventHandle = await captureLastKeydown(page)
-
- async def testEnterKey(key: str, expectedKey: str, expectedCode: str) -> None:
- await page.keyboard.press(key)
- lastEvent = await lastEventHandle.json_value()
- assert lastEvent["key"] == expectedKey
- assert lastEvent["code"] == expectedCode
- value = await page.eval_on_selector("textarea", "t => t.value")
- assert value == "\n"
- await page.eval_on_selector("textarea", "t => t.value = ''")
-
- await testEnterKey("Enter", "Enter", "Enter")
- await testEnterKey("NumpadEnter", "Enter", "NumpadEnter")
- await testEnterKey("\n", "Enter", "Enter")
- await testEnterKey("\r", "Enter", "Enter")
-
-
-async def test_should_throw_unknown_keys(page: Page, server: Server) -> None:
- with pytest.raises(Error) as exc:
- await page.keyboard.press("NotARealKey")
- assert exc.value.message == 'Keyboard.press: Unknown key: "NotARealKey"'
-
- with pytest.raises(Error) as exc:
- await page.keyboard.press("ё")
- assert exc.value.message == 'Keyboard.press: Unknown key: "ё"'
-
- with pytest.raises(Error) as exc:
- await page.keyboard.press("😊")
- assert exc.value.message == 'Keyboard.press: Unknown key: "😊"'
-
-
-async def test_should_type_emoji(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/textarea.html")
- await page.type("textarea", "👹 Tokyo street Japan 🇯🇵")
- assert (
- await page.eval_on_selector("textarea", "textarea => textarea.value")
- == "👹 Tokyo street Japan 🇯🇵"
- )
-
-
-async def test_should_type_emoji_into_an_iframe(page: Page, server: Server, utils: Utils) -> None:
- await page.goto(server.EMPTY_PAGE)
- await utils.attach_frame(page, "emoji-test", server.PREFIX + "/input/textarea.html")
- frame = page.frames[1]
- textarea = await frame.query_selector("textarea")
- assert textarea
- await textarea.type("👹 Tokyo street Japan 🇯🇵")
- assert (
- await frame.eval_on_selector("textarea", "textarea => textarea.value")
- == "👹 Tokyo street Japan 🇯🇵"
- )
-
-
-async def test_should_handle_select_all(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/textarea.html")
- textarea = await page.query_selector("textarea")
- assert textarea
- await textarea.type("some text")
- await page.keyboard.down("ControlOrMeta")
- await page.keyboard.press("a")
- await page.keyboard.up("ControlOrMeta")
- await page.keyboard.press("Backspace")
- assert await page.eval_on_selector("textarea", "textarea => textarea.value") == ""
-
-
-async def test_should_be_able_to_prevent_select_all(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/textarea.html")
- textarea = await page.query_selector("textarea")
- assert textarea
- await textarea.type("some text")
- await page.eval_on_selector(
- "textarea",
- """textarea => {
- textarea.addEventListener('keydown', event => {
- if (event.key === 'a' && (event.metaKey || event.ctrlKey))
- event.preventDefault();
- }, false);
- }""",
- )
-
- await page.keyboard.down("ControlOrMeta")
- await page.keyboard.press("a")
- await page.keyboard.up("ControlOrMeta")
- await page.keyboard.press("Backspace")
- assert await page.eval_on_selector("textarea", "textarea => textarea.value") == "some tex"
-
-
-@pytest.mark.only_platform("darwin")
-@pytest.mark.skip_browser("firefox") # Upstream issue
-async def test_should_support_macos_shortcuts(
- page: Page, server: Server, is_firefox: bool, is_mac: bool
-) -> None:
- await page.goto(server.PREFIX + "/input/textarea.html")
- textarea = await page.query_selector("textarea")
- assert textarea
- await textarea.type("some text")
- # select one word backwards
- await page.keyboard.press("Shift+Control+Alt+KeyB")
- await page.keyboard.press("Backspace")
- assert await page.eval_on_selector("textarea", "textarea => textarea.value") == "some "
-
-
-async def test_should_press_the_meta_key(page: Page) -> None:
- lastEvent = await captureLastKeydown(page)
- await page.keyboard.press("Meta")
- v = await lastEvent.json_value()
- metaKey = v["metaKey"]
- key = v["key"]
- code = v["code"]
- assert key == "Meta"
- assert code == "MetaLeft"
- assert metaKey
-
-
-async def test_should_work_after_a_cross_origin_navigation(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/empty.html")
- await page.goto(server.CROSS_PROCESS_PREFIX + "/empty.html")
- lastEvent = await captureLastKeydown(page)
- await page.keyboard.press("a")
- assert await lastEvent.evaluate("l => l.key") == "a"
-
-
-# event.keyIdentifier has been removed from all browsers except WebKit
-@pytest.mark.only_browser("webkit")
-async def test_should_expose_keyIdentifier_in_webkit(page: Page, server: Server) -> None:
- lastEvent = await captureLastKeydown(page)
- keyMap = {
- "ArrowUp": "Up",
- "ArrowDown": "Down",
- "ArrowLeft": "Left",
- "ArrowRight": "Right",
- "Backspace": "U+0008",
- "Tab": "U+0009",
- "Delete": "U+007F",
- "a": "U+0041",
- "b": "U+0042",
- "F12": "F12",
- }
- for key, keyIdentifier in keyMap.items():
- await page.keyboard.press(key)
- assert await lastEvent.evaluate("e => e.keyIdentifier") == keyIdentifier
-
-
-async def test_should_scroll_with_pagedown(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/scrollable.html")
- # A click is required for WebKit to send the event into the body.
- await page.click("body")
- await page.keyboard.press("PageDown")
- # We can't wait for the scroll to finish, so just wait for it to start.
- await page.wait_for_function("() => scrollY > 0")
diff --git a/tests/async/test_launcher.py.disabled b/tests/async/test_launcher.py.disabled
deleted file mode 100644
index d29b209..0000000
--- a/tests/async/test_launcher.py.disabled
+++ /dev/null
@@ -1,145 +0,0 @@
-# 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 os
-from pathlib import Path
-from typing import Dict, Optional
-
-import pytest
-
-from playwright.async_api import BrowserType, Error
-from tests.utils import TARGET_CLOSED_ERROR_MESSAGE
-
-
-async def test_browser_type_launch_should_reject_all_promises_when_browser_is_closed(
- browser_type: BrowserType, launch_arguments: Dict
-) -> None:
- browser = await browser_type.launch(**launch_arguments)
- page = await (await browser.new_context()).new_page()
- never_resolves = asyncio.create_task(page.evaluate("() => new Promise(r => {})"))
- await page.close()
- with pytest.raises(Error) as exc:
- await never_resolves
- assert TARGET_CLOSED_ERROR_MESSAGE in exc.value.message
-
-
-@pytest.mark.skip_browser("firefox")
-async def test_browser_type_launch_should_throw_if_page_argument_is_passed(
- browser_type: BrowserType, launch_arguments: Dict
-) -> None:
- with pytest.raises(Error) as exc:
- await browser_type.launch(**launch_arguments, args=["http://example.com"])
- assert "can not specify page" in exc.value.message
-
-
-async def test_browser_type_launch_should_reject_if_launched_browser_fails_immediately(
- browser_type: BrowserType, launch_arguments: Dict, assetdir: Path
-) -> None:
- with pytest.raises(Error):
- await browser_type.launch(
- **launch_arguments,
- executable_path=assetdir / "dummy_bad_browser_executable.js",
- )
-
-
-async def test_browser_type_launch_should_reject_if_executable_path_is_invalid(
- browser_type: BrowserType, launch_arguments: Dict
-) -> None:
- with pytest.raises(Error) as exc:
- await browser_type.launch(
- **launch_arguments, executable_path="random-invalid-path"
- )
- assert "executable doesn't exist" in exc.value.message
-
-
-async def test_browser_type_executable_path_should_work(
- browser_type: BrowserType, browser_channel: str
-) -> None:
- if browser_channel:
- return
- executable_path = browser_type.executable_path
- assert os.path.exists(executable_path)
- assert os.path.realpath(executable_path) == os.path.realpath(executable_path)
-
-
-async def test_browser_type_name_should_work(
- browser_type: BrowserType, is_webkit: bool, is_firefox: bool, is_chromium: bool
-) -> None:
- if is_webkit:
- assert browser_type.name == "webkit"
- elif is_firefox:
- assert browser_type.name == "firefox"
- elif is_chromium:
- assert browser_type.name == "chromium"
- else:
- raise ValueError("Unknown browser")
-
-
-async def test_browser_close_should_fire_close_event_for_all_contexts(
- browser_type: BrowserType, launch_arguments: Dict
-) -> None:
- browser = await browser_type.launch(**launch_arguments)
- context = await browser.new_context()
- closed = []
- context.on("close", lambda _: closed.append(True))
- await browser.close()
- assert closed == [True]
-
-
-async def test_browser_close_should_be_callable_twice(
- browser_type: BrowserType, launch_arguments: Dict
-) -> None:
- browser = await browser_type.launch(**launch_arguments)
- await asyncio.gather(
- browser.close(),
- browser.close(),
- )
- await browser.close()
-
-
-@pytest.mark.only_browser("chromium")
-async def test_browser_launch_should_return_background_pages(
- browser_type: BrowserType,
- tmpdir: Path,
- browser_channel: Optional[str],
- assetdir: Path,
- launch_arguments: Dict,
-) -> None:
- if browser_channel:
- pytest.skip()
-
- extension_path = str(assetdir / "simple-extension")
- context = await browser_type.launch_persistent_context(
- str(tmpdir),
- **{
- **launch_arguments,
- "headless": False,
- "args": [
- f"--disable-extensions-except={extension_path}",
- f"--load-extension={extension_path}",
- ],
- },
- )
- background_page = None
- if len(context.background_pages):
- background_page = context.background_pages[0]
- else:
- background_page = await context.wait_for_event("backgroundpage")
- assert background_page
- assert background_page in context.background_pages
- assert background_page not in context.pages
- await context.close()
- assert len(context.background_pages) == 0
- assert len(context.pages) == 0
diff --git a/tests/async/test_listeners.py b/tests/async/test_listeners.py
deleted file mode 100644
index 5185fd4..0000000
--- a/tests/async/test_listeners.py
+++ /dev/null
@@ -1,32 +0,0 @@
-# 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.
-
-from playwright.async_api import Page, Response
-from tests.server import Server
-
-
-async def test_listeners(page: Page, server: Server) -> None:
- log = []
-
- def print_response(response: Response) -> None:
- log.append(response)
-
- page.on("response", print_response)
- await page.goto(f"{server.PREFIX}/input/textarea.html")
- assert len(log) > 0
- page.remove_listener("response", print_response)
-
- log = []
- await page.goto(f"{server.PREFIX}/input/textarea.html")
- assert len(log) == 0
diff --git a/tests/async/test_locators.py b/tests/async/test_locators.py
deleted file mode 100644
index 93aad1c..0000000
--- a/tests/async/test_locators.py
+++ /dev/null
@@ -1,1039 +0,0 @@
-# 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
-import re
-import traceback
-from typing import Callable
-from urllib.parse import urlparse
-
-import pytest
-from playwright._impl._path_utils import get_file_dirname
-from playwright.async_api import Error, Page, expect
-
-from tests.server import Server
-
-_dirname = get_file_dirname()
-FILE_TO_UPLOAD = _dirname / ".." / "assets/file-to-upload.txt"
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_locators_click_should_work(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/button.html")
- button = page.locator("button")
- await button.click()
- assert await page.evaluate("window['result']") == "Clicked"
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_locators_click_should_work_with_node_removed(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/button.html")
- await page.evaluate("delete window['Node']")
- button = page.locator("button")
- await button.click()
- assert await page.evaluate("window['result']") == "Clicked"
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_locators_click_should_work_for_text_nodes(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/button.html")
- await page.evaluate(
- """() => {
- window['double'] = false;
- const button = document.querySelector('button');
- button.addEventListener('dblclick', event => {
- window['double'] = true;
- });
- }"""
- )
- button = page.locator("button")
- await button.dblclick()
- assert await page.evaluate("double") is True
- assert await page.evaluate("result") == "Clicked"
-
-
-async def test_locators_should_have_repr(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/button.html")
- button = page.locator("button")
- await button.click()
- assert (
- str(button)
- == f" selector='button'>"
- )
-
-
-async def test_locators_get_attribute_should_work(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/dom.html")
- button = page.locator("#outer")
- assert await button.get_attribute("name") == "value"
- assert await button.get_attribute("foo") is None
-
-
-async def test_locators_input_value_should_work(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/dom.html")
- await page.fill("#textarea", "input value")
- text_area = page.locator("#textarea")
- assert await text_area.input_value() == "input value"
-
-
-async def test_locators_inner_html_should_work(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/dom.html")
- locator = page.locator("#outer")
- assert await locator.inner_html() == 'Text,\nmore text
'
-
-
-async def test_locators_inner_text_should_work(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/dom.html")
- locator = page.locator("#inner")
- assert await locator.inner_text() == "Text, more text"
-
-
-async def test_locators_text_content_should_work(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/dom.html")
- locator = page.locator("#inner")
- assert await locator.text_content() == "Text,\nmore text"
-
-
-async def test_locators_is_hidden_and_is_visible_should_work(page: Page) -> None:
- await page.set_content("Hi
")
-
- div = page.locator("div")
- assert await div.is_visible() is True
- assert await div.is_hidden() is False
-
- span = page.locator("span")
- assert await span.is_visible() is False
- assert await span.is_hidden() is True
-
-
-async def test_locators_is_enabled_and_is_disabled_should_work(page: Page) -> None:
- await page.set_content(
- """
- button1
- button2
- div
- """
- )
-
- div = page.locator("div")
- assert await div.is_enabled() is True
- assert await div.is_disabled() is False
-
- button1 = page.locator(':text("button1")')
- assert await button1.is_enabled() is False
- assert await button1.is_disabled() is True
-
- button1 = page.locator(':text("button2")')
- assert await button1.is_enabled() is True
- assert await button1.is_disabled() is False
-
-
-async def test_locators_is_editable_should_work(page: Page) -> None:
- await page.set_content(
- """
-
- """
- )
-
- input1 = page.locator("#input1")
- assert await input1.is_editable() is False
-
- input2 = page.locator("#input2")
- assert await input2.is_editable() is True
-
-
-async def test_locators_is_checked_should_work(page: Page) -> None:
- await page.set_content(
- """
- Not a checkbox
- """
- )
-
- element = page.locator("input")
- assert await element.is_checked() is True
- await element.evaluate("e => e.checked = false")
- assert await element.is_checked() is False
-
-
-async def test_locators_all_text_contents_should_work(page: Page) -> None:
- await page.set_content(
- """
- A
B
C
- """
- )
-
- element = page.locator("div")
- assert await element.all_text_contents() == ["A", "B", "C"]
-
-
-async def test_locators_all_inner_texts(page: Page) -> None:
- await page.set_content(
- """
- A
B
C
- """
- )
-
- element = page.locator("div")
- assert await element.all_inner_texts() == ["A", "B", "C"]
-
-
-async def test_locators_should_query_existing_element(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/playground.html")
- await page.set_content(
- """"""
- )
- html = page.locator("html")
- second = html.locator(".second")
- inner = second.locator(".inner")
- assert await page.evaluate("e => e.textContent", await inner.element_handle()) == "A"
-
-
-async def test_locators_evaluate_handle_should_work(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/dom.html")
- outer = page.locator("#outer")
- inner = outer.locator("#inner")
- check = inner.locator("#check")
- text = await inner.evaluate_handle("e => e.firstChild")
- await page.evaluate("1 + 1")
- assert (
- str(outer)
- == f" selector='#outer'>"
- )
- assert (
- str(inner)
- == f" selector='#outer >> #inner'>"
- )
- assert str(text) == "JSHandle@#text=Text,↵more text"
- assert (
- str(check)
- == f" selector='#outer >> #inner >> #check'>"
- )
-
-
-async def test_locators_should_query_existing_elements(page: Page) -> None:
- await page.set_content("""A
B
""")
- html = page.locator("html")
- elements = await html.locator("div").element_handles()
- assert len(elements) == 2
- result = []
- for element in elements:
- result.append(await page.evaluate("e => e.textContent", element))
- assert result == ["A", "B"]
-
-
-async def test_locators_return_empty_array_for_non_existing_elements(
- page: Page,
-) -> None:
- await page.set_content("""A
B
""")
- html = page.locator("html")
- elements = await html.locator("abc").element_handles()
- assert len(elements) == 0
- assert elements == []
-
-
-async def test_locators_evaluate_all_should_work(page: Page) -> None:
- await page.set_content(
- """"""
- )
- tweet = page.locator(".tweet .like")
- content = await tweet.evaluate_all("nodes => nodes.map(n => n.innerText)")
- assert content == ["100", "10"]
-
-
-async def test_locators_evaluate_all_should_work_with_missing_selector(
- page: Page,
-) -> None:
- await page.set_content("""not-a-child-div
nodes.length")
- assert nodes_length == 0
-
-
-async def test_locators_hover_should_work(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/scrollable.html")
- button = page.locator("#button-6")
- await button.hover()
- assert await page.evaluate("document.querySelector('button:hover').id") == "button-6"
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_locators_fill_should_work(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/textarea.html")
- button = page.locator("input")
- await button.fill("some value")
- assert await page.evaluate("result") == "some value"
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_locators_clear_should_work(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/textarea.html")
- button = page.locator("input")
- await button.fill("some value")
- assert await page.evaluate("result") == "some value"
- await button.clear()
- assert await page.evaluate("result") == ""
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_locators_check_should_work(page: Page) -> None:
- await page.set_content(" ")
- button = page.locator("input")
- await button.check()
- assert await page.evaluate("checkbox.checked") is True
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_locators_uncheck_should_work(page: Page) -> None:
- await page.set_content(" ")
- button = page.locator("input")
- await button.uncheck()
- assert await page.evaluate("checkbox.checked") is False
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_locators_select_option_should_work(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/select.html")
- select = page.locator("select")
- await select.select_option("blue")
- assert await page.evaluate("result.onInput") == ["blue"]
- assert await page.evaluate("result.onChange") == ["blue"]
-
-
-async def test_locators_focus_should_work(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/button.html")
- button = page.locator("button")
- assert await button.evaluate("button => document.activeElement === button") is False
- await button.focus()
- assert await button.evaluate("button => document.activeElement === button") is True
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_locators_dispatch_event_should_work(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/button.html")
- button = page.locator("button")
- await button.dispatch_event("click")
- assert await page.evaluate("result") == "Clicked"
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_locators_should_upload_a_file(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/fileupload.html")
- input = page.locator("input[type=file]")
-
- file_path = os.path.relpath(FILE_TO_UPLOAD, os.getcwd())
- await input.set_input_files(file_path)
- assert (
- await page.evaluate("e => e.files[0].name", await input.element_handle())
- == "file-to-upload.txt"
- )
-
-
-async def test_locators_should_press(page: Page) -> None:
- await page.set_content(" ")
- await page.locator("input").press("h")
- assert await page.eval_on_selector("input", "input => input.value") == "h"
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_locators_should_scroll_into_view(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/offscreenbuttons.html")
- for i in range(11):
- button = page.locator(f"#btn{i}")
- before = await button.evaluate(
- "button => button.getBoundingClientRect().right - window.innerWidth"
- )
- assert before == 10 * i
- await button.scroll_into_view_if_needed()
- after = await button.evaluate(
- "button => button.getBoundingClientRect().right - window.innerWidth"
- )
- assert after <= 0
- await page.evaluate("window.scrollTo(0, 0)")
-
-
-async def test_locators_should_select_textarea(
- page: Page, server: Server, browser_name: str
-) -> None:
- await page.goto(server.PREFIX + "/input/textarea.html")
- textarea = page.locator("textarea")
- await textarea.evaluate("textarea => textarea.value = 'some value'")
- await textarea.select_text()
- if browser_name == "firefox" or browser_name == "webkit":
- assert await textarea.evaluate("el => el.selectionStart") == 0
- assert await textarea.evaluate("el => el.selectionEnd") == 10
- else:
- assert await page.evaluate("window.getSelection().toString()") == "some value"
-
-
-async def test_locators_should_type(page: Page) -> None:
- await page.set_content(" ")
- await page.locator("input").type("hello")
- assert await page.eval_on_selector("input", "input => input.value") == "hello"
-
-
-async def test_locators_should_press_sequentially(page: Page) -> None:
- await page.set_content(" ")
- await page.locator("input").press_sequentially("hello")
- assert await page.eval_on_selector("input", "input => input.value") == "hello"
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_locators_should_screenshot(
- page: Page, server: Server, assert_to_be_golden: Callable[[bytes, str], None]
-) -> None:
- await page.set_viewport_size(
- {
- "width": 500,
- "height": 500,
- }
- )
- await page.goto(server.PREFIX + "/grid.html")
- await page.evaluate("window.scrollBy(50, 100)")
- element = page.locator(".box:nth-of-type(3)")
- assert_to_be_golden(await element.screenshot(), "screenshot-element-bounding-box.png")
-
-
-async def test_locators_should_return_bounding_box(page: Page, server: Server) -> None:
- await page.set_viewport_size(
- {
- "width": 500,
- "height": 500,
- }
- )
- await page.goto(server.PREFIX + "/grid.html")
- element = page.locator(".box:nth-of-type(13)")
- box = await element.bounding_box()
- assert box == {
- "x": 100,
- "y": 50,
- "width": 50,
- "height": 50,
- }
-
-
-async def test_locators_should_respect_first_and_last(page: Page) -> None:
- await page.set_content(
- """
- """
- )
- assert await page.locator("div >> p").count() == 6
- assert await page.locator("div").locator("p").count() == 6
- assert await page.locator("div").first.locator("p").count() == 1
- assert await page.locator("div").last.locator("p").count() == 3
-
-
-async def test_locators_should_respect_nth(page: Page) -> None:
- await page.set_content(
- """
- """
- )
- assert await page.locator("div >> p").nth(0).count() == 1
- assert await page.locator("div").nth(1).locator("p").count() == 2
- assert await page.locator("div").nth(2).locator("p").count() == 3
-
-
-async def test_locators_should_throw_on_capture_without_nth(page: Page) -> None:
- await page.set_content(
- """
-
- """
- )
- with pytest.raises(Error, match="Can't query n-th element"):
- await page.locator("*css=div >> p").nth(1).click()
-
-
-async def test_locators_should_throw_due_to_strictness(page: Page) -> None:
- await page.set_content(
- """
- A
B
- """
- )
- with pytest.raises(Error, match="strict mode violation"):
- await page.locator("div").is_visible()
-
-
-async def test_locators_should_throw_due_to_strictness_2(page: Page) -> None:
- await page.set_content(
- """
- One Two
- """
- )
- with pytest.raises(Error, match="strict mode violation"):
- await page.locator("option").evaluate("e => {}")
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_locators_set_checked(page: Page) -> None:
- await page.set_content("` `")
- locator = page.locator("input")
- await locator.set_checked(True)
- assert await page.evaluate("checkbox.checked")
- await locator.set_checked(False)
- assert await page.evaluate("checkbox.checked") is False
-
-
-async def test_locators_wait_for(page: Page) -> None:
- await page.set_content("
")
- locator = page.locator("div")
- task = locator.wait_for()
- await page.eval_on_selector("div", "div => div.innerHTML = 'target '")
- await task
- assert await locator.text_content() == "target"
-
-
-async def test_should_wait_for_hidden(page: Page) -> None:
- await page.set_content("target
")
- locator = page.locator("span")
- task = locator.wait_for(state="hidden")
- await page.eval_on_selector("div", "div => div.innerHTML = ''")
- await task
-
-
-async def test_should_combine_visible_with_other_selectors(page: Page) -> None:
- await page.set_content(
- """
-
Hidden data0
-
visible data1
-
Hidden data1
-
visible data2
-
Hidden data1
-
visible data3
-
- """
- )
- locator = page.locator(".item >> visible=true").nth(1)
- await expect(locator).to_have_text("visible data2")
- await expect(page.locator(".item >> visible=true >> text=data3")).to_have_text("visible data3")
-
-
-async def test_locator_count_should_work_with_deleted_map_in_main_world(
- page: Page,
-) -> None:
- await page.evaluate("Map = 1")
- await page.locator("#searchResultTableDiv .x-grid3-row").count()
- await expect(page.locator("#searchResultTableDiv .x-grid3-row")).to_have_count(0)
-
-
-async def test_locator_locator_and_framelocator_locator_should_accept_locator(
- page: Page,
-) -> None:
- await page.set_content(
- """
-
-
- """
- )
-
- input_locator = page.locator("input")
- assert await input_locator.input_value() == "outer"
- assert await page.locator("div").locator(input_locator).input_value() == "outer"
- assert await page.frame_locator("iframe").locator(input_locator).input_value() == "inner"
- assert (
- await page.frame_locator("iframe").locator("div").locator(input_locator).input_value()
- == "inner"
- )
-
- div_locator = page.locator("div")
- assert await div_locator.locator("input").input_value() == "outer"
- assert (
- await page.frame_locator("iframe").locator(div_locator).locator("input").input_value()
- == "inner"
- )
-
-
-async def route_iframe(page: Page) -> None:
- await page.route(
- "**/empty.html",
- lambda route: route.fulfill(
- body='',
- content_type="text/html",
- ),
- )
- await page.route(
- "**/iframe.html",
- lambda route: route.fulfill(
- body="""
-
- Hello iframe
-
-
- 1
- 2
- """,
- content_type="text/html",
- ),
- )
- await page.route(
- "**/iframe-2.html",
- lambda route: route.fulfill(
- body="Hello nested iframe ",
- content_type="text/html",
- ),
- )
-
-
-async def test_locators_frame_should_work_with_iframe(page: Page, server: Server) -> None:
- await route_iframe(page)
- await page.goto(server.EMPTY_PAGE)
- button = page.frame_locator("iframe").locator("button")
- await button.wait_for()
- assert await button.inner_text() == "Hello iframe"
- await button.click()
-
-
-async def test_locators_frame_should_work_for_nested_iframe(page: Page, server: Server) -> None:
- await route_iframe(page)
- await page.goto(server.EMPTY_PAGE)
- button = page.frame_locator("iframe").frame_locator("iframe").locator("button")
- await button.wait_for()
- assert await button.inner_text() == "Hello nested iframe"
- await button.click()
-
-
-async def test_locators_frame_should_work_with_locator_frame_locator(
- page: Page, server: Server
-) -> None:
- await route_iframe(page)
- await page.goto(server.EMPTY_PAGE)
- button = page.locator("body").frame_locator("iframe").locator("button")
- await button.wait_for()
- assert await button.inner_text() == "Hello iframe"
- await button.click()
-
-
-async def test_locator_content_frame_should_work(page: Page, server: Server) -> None:
- await route_iframe(page)
- await page.goto(server.EMPTY_PAGE)
- locator = page.locator("iframe")
- frame_locator = locator.content_frame
- button = frame_locator.locator("button")
- assert await button.inner_text() == "Hello iframe"
- await expect(button).to_have_text("Hello iframe")
- await button.click()
-
-
-async def test_frame_locator_owner_should_work(page: Page, server: Server) -> None:
- await route_iframe(page)
- await page.goto(server.EMPTY_PAGE)
- frame_locator = page.frame_locator("iframe")
- locator = frame_locator.owner
- await expect(locator).to_be_visible()
- assert await locator.get_attribute("name") == "frame1"
-
-
-async def route_ambiguous(page: Page) -> None:
- await page.route(
- "**/empty.html",
- lambda route: route.fulfill(
- body="""
-
-
-
- """,
- content_type="text/html",
- ),
- )
- await page.route(
- "**/iframe-*",
- lambda route: route.fulfill(
- body=f"Hello from {urlparse(route.request.url).path[1:]} ",
- content_type="text/html",
- ),
- )
-
-
-async def test_locator_frame_locator_should_throw_on_ambiguity(page: Page, server: Server) -> None:
- await route_ambiguous(page)
- await page.goto(server.EMPTY_PAGE)
- button = page.locator("body").frame_locator("iframe").locator("button")
- with pytest.raises(
- Error,
- match=r'.*strict mode violation: locator\("body"\)\.locator\("iframe"\) resolved to 3 elements.*',
- ):
- await button.wait_for()
-
-
-async def test_locator_frame_locator_should_not_throw_on_first_last_nth(
- page: Page, server: Server
-) -> None:
- await route_ambiguous(page)
- await page.goto(server.EMPTY_PAGE)
- button1 = page.locator("body").frame_locator("iframe").first.locator("button")
- assert await button1.text_content() == "Hello from iframe-1.html"
- button2 = page.locator("body").frame_locator("iframe").nth(1).locator("button")
- assert await button2.text_content() == "Hello from iframe-2.html"
- button3 = page.locator("body").frame_locator("iframe").last.locator("button")
- assert await button3.text_content() == "Hello from iframe-3.html"
-
-
-async def test_drag_to(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/drag-n-drop.html")
- await page.locator("#source").drag_to(page.locator("#target"))
- assert (
- await page.eval_on_selector(
- "#target", "target => target.contains(document.querySelector('#source'))"
- )
- is True
- )
-
-
-async def test_drag_to_with_position(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- await page.set_content(
- """
-
-
-
-
- """
- )
- events_handle = await page.evaluate_handle(
- """
- () => {
- const events = [];
- document.getElementById('red').addEventListener('mousedown', event => {
- events.push({
- type: 'mousedown',
- x: event.offsetX,
- y: event.offsetY,
- });
- });
- document.getElementById('blue').addEventListener('mouseup', event => {
- events.push({
- type: 'mouseup',
- x: event.offsetX,
- y: event.offsetY,
- });
- });
- return events;
- }
- """
- )
- await page.locator("#red").drag_to(
- page.locator("#blue"),
- source_position={"x": 34, "y": 7},
- target_position={"x": 10, "y": 20},
- )
- assert await events_handle.json_value() == [
- {"type": "mousedown", "x": 34, "y": 7},
- {"type": "mouseup", "x": 10, "y": 20},
- ]
-
-
-async def test_locator_query_should_filter_by_text(page: Page, server: Server) -> None:
- await page.set_content("Foobar
Bar
")
- await expect(page.locator("div", has_text="Foo")).to_have_text("Foobar")
-
-
-async def test_locator_query_should_filter_by_text_2(page: Page, server: Server) -> None:
- await page.set_content("foo hello world bar
")
- await expect(page.locator("div", has_text="hello world")).to_have_text("foo hello world bar")
-
-
-async def test_locator_query_should_filter_by_regex(page: Page, server: Server) -> None:
- await page.set_content("Foobar
Bar
")
- await expect(page.locator("div", has_text=re.compile(r"Foo.*"))).to_have_text("Foobar")
-
-
-async def test_locator_query_should_filter_by_text_with_quotes(page: Page, server: Server) -> None:
- await page.set_content('Hello "world"
Hello world
')
- await expect(page.locator("div", has_text='Hello "world"')).to_have_text('Hello "world"')
-
-
-async def test_locator_query_should_filter_by_regex_with_quotes(page: Page, server: Server) -> None:
- await page.set_content('Hello "world"
Hello world
')
- await expect(page.locator("div", has_text=re.compile('Hello "world"'))).to_have_text(
- 'Hello "world"'
- )
-
-
-async def test_locator_query_should_filter_by_regex_and_regexp_flags(
- page: Page, server: Server
-) -> None:
- await page.set_content('Hello "world"
Hello world
')
- await expect(
- page.locator("div", has_text=re.compile('hElLo "world', re.IGNORECASE))
- ).to_have_text('Hello "world"')
-
-
-async def test_locator_should_return_page(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/frames/two-frames.html")
- outer = page.locator("#outer")
- assert outer.page == page
-
- inner = outer.locator("#inner")
- assert inner.page == page
-
- in_frame = page.frames[1].locator("div")
- assert in_frame.page == page
-
-
-async def test_locator_should_support_has_locator(page: Page, server: Server) -> None:
- await page.set_content("hello
world
")
- await expect(page.locator("div", has=page.locator("text=world"))).to_have_count(1)
- assert (
- await page.locator("div", has=page.locator("text=world")).evaluate("e => e.outerHTML")
- == "world
"
- )
- await expect(page.locator("div", has=page.locator('text="hello"'))).to_have_count(1)
- assert (
- await page.locator("div", has=page.locator('text="hello"')).evaluate("e => e.outerHTML")
- == "hello
"
- )
- await expect(page.locator("div", has=page.locator("xpath=./span"))).to_have_count(2)
- await expect(page.locator("div", has=page.locator("span"))).to_have_count(2)
- await expect(page.locator("div", has=page.locator("span", has_text="wor"))).to_have_count(1)
- assert (
- await page.locator("div", has=page.locator("span", has_text="wor")).evaluate(
- "e => e.outerHTML"
- )
- == "world
"
- )
- await expect(
- page.locator(
- "div",
- has=page.locator("span"),
- has_text="wor",
- )
- ).to_have_count(1)
-
-
-async def test_locator_should_enforce_same_frame_for_has_locator(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/frames/two-frames.html")
- child = page.frames[1]
- with pytest.raises(Error) as exc_info:
- page.locator("div", has=child.locator("span"))
- assert 'Inner "has" locator must belong to the same frame.' in exc_info.value.message
-
-
-async def test_locator_should_support_locator_or(page: Page, server: Server) -> None:
- await page.set_content("hello
world ")
- await expect(page.locator("div").or_(page.locator("span"))).to_have_count(2)
- await expect(page.locator("div").or_(page.locator("span"))).to_have_text(["hello", "world"])
- await expect(
- page.locator("span").or_(page.locator("article")).or_(page.locator("div"))
- ).to_have_text(["hello", "world"])
- await expect(page.locator("article").or_(page.locator("someting"))).to_have_count(0)
- await expect(page.locator("article").or_(page.locator("div"))).to_have_text("hello")
- await expect(page.locator("article").or_(page.locator("span"))).to_have_text("world")
- await expect(page.locator("div").or_(page.locator("article"))).to_have_text("hello")
- await expect(page.locator("span").or_(page.locator("article"))).to_have_text("world")
-
-
-async def test_locator_should_support_locator_locator_with_and_or(page: Page) -> None:
- await page.set_content(
- """
- one two three
- four
- five
- """
- )
-
- await expect(page.locator("div").locator(page.locator("button"))).to_have_text(["three"])
- await expect(
- page.locator("div").locator(page.locator("button").or_(page.locator("span")))
- ).to_have_text(["two", "three"])
- await expect(page.locator("button").or_(page.locator("span"))).to_have_text(
- ["two", "three", "four", "five"]
- )
-
- await expect(
- page.locator("div").locator(page.locator("button").and_(page.get_by_role("button")))
- ).to_have_text(["three"])
- await expect(page.locator("button").and_(page.get_by_role("button"))).to_have_text(
- ["three", "five"]
- )
-
-
-async def test_locator_highlight_should_work(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/grid.html")
- await page.locator(".box").nth(3).highlight()
- assert await page.locator("x-pw-glass").is_visible()
-
-
-async def test_should_support_locator_that(page: Page) -> None:
- await page.set_content(
- ""
- )
-
- await expect(page.locator("div").filter(has_text="hello")).to_have_count(1)
- await expect(page.locator("div", has_text="hello").filter(has_text="hello")).to_have_count(1)
- await expect(page.locator("div", has_text="hello").filter(has_text="world")).to_have_count(0)
- await expect(page.locator("section", has_text="hello").filter(has_text="world")).to_have_count(
- 1
- )
- await expect(page.locator("div").filter(has_text="hello").locator("span")).to_have_count(1)
- await expect(
- page.locator("div").filter(has=page.locator("span", has_text="world"))
- ).to_have_count(1)
- await expect(page.locator("div").filter(has=page.locator("span"))).to_have_count(2)
- await expect(
- page.locator("div").filter(
- has=page.locator("span"),
- has_text="world",
- )
- ).to_have_count(1)
-
-
-async def test_should_filter_by_case_insensitive_regex_in_a_child(page: Page) -> None:
- await page.set_content('
Title Text ')
- await expect(page.locator("div", has_text=re.compile(r"^title text$", re.I))).to_have_text(
- "Title Text"
- )
-
-
-async def test_should_filter_by_case_insensitive_regex_in_multiple_children(
- page: Page,
-) -> None:
- await page.set_content('
Title Text ')
- await expect(page.locator("div", has_text=re.compile(r"^title text$", re.I))).to_have_class(
- "test"
- )
-
-
-async def test_should_filter_by_regex_with_special_symbols(page: Page) -> None:
- await page.set_content('
First/"and" Second\\ ')
- await expect(
- page.locator("div", has_text=re.compile(r'^first\/".*"second\\$', re.S | re.I))
- ).to_have_class("test")
-
-
-async def test_should_support_locator_filter(page: Page) -> None:
- await page.set_content(
- ""
- )
-
- await expect(page.locator("div").filter(has_text="hello")).to_have_count(1)
- await expect(page.locator("div", has_text="hello").filter(has_text="hello")).to_have_count(1)
- await expect(page.locator("div", has_text="hello").filter(has_text="world")).to_have_count(0)
- await expect(page.locator("section", has_text="hello").filter(has_text="world")).to_have_count(
- 1
- )
- await expect(page.locator("div").filter(has_text="hello").locator("span")).to_have_count(1)
- await expect(
- page.locator("div").filter(has=page.locator("span", has_text="world"))
- ).to_have_count(1)
- await expect(page.locator("div").filter(has=page.locator("span"))).to_have_count(2)
- await expect(
- page.locator("div").filter(
- has=page.locator("span"),
- has_text="world",
- )
- ).to_have_count(1)
- await expect(
- page.locator("div").filter(has_not=page.locator("span", has_text="world"))
- ).to_have_count(1)
- await expect(page.locator("div").filter(has_not=page.locator("section"))).to_have_count(2)
- await expect(page.locator("div").filter(has_not=page.locator("span"))).to_have_count(0)
-
- await expect(page.locator("div").filter(has_not_text="hello")).to_have_count(1)
- await expect(page.locator("div").filter(has_not_text="foo")).to_have_count(2)
-
-
-async def test_locators_should_support_locator_and(page: Page, server: Server) -> None:
- await page.set_content(
- """
- hello
world
- hello2 world2
- """
- )
- await expect(page.locator("div").and_(page.locator("div"))).to_have_count(2)
- await expect(page.locator("div").and_(page.get_by_test_id("foo"))).to_have_text(["hello"])
- await expect(page.locator("div").and_(page.get_by_test_id("bar"))).to_have_text(["world"])
- await expect(page.get_by_test_id("foo").and_(page.locator("div"))).to_have_text(["hello"])
- await expect(page.get_by_test_id("bar").and_(page.locator("span"))).to_have_text(["world2"])
- await expect(
- page.locator("span").and_(page.get_by_test_id(re.compile("bar|foo")))
- ).to_have_count(2)
-
-
-async def test_locators_has_does_not_encode_unicode(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- locators = [
- page.locator("button", has_text="Драматург"),
- page.locator("button", has_text=re.compile("Драматург")),
- page.locator("button", has=page.locator("text=Драматург")),
- ]
- for locator in locators:
- with pytest.raises(Error) as exc_info:
- await locator.click(timeout=1_000)
- assert "Драматург" in exc_info.value.message
-
-
-async def test_locators_should_focus_and_blur_a_button(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/button.html")
- button = page.locator("button")
- assert not await button.evaluate("button => document.activeElement === button")
-
- focused = False
- blurred = False
-
- async def focus_event() -> None:
- nonlocal focused
- focused = True
-
- async def blur_event() -> None:
- nonlocal blurred
- blurred = True
-
- await page.expose_function("focusEvent", focus_event)
- await page.expose_function("blurEvent", blur_event)
- await button.evaluate(
- """button => {
- button.addEventListener('focus', window['focusEvent']);
- button.addEventListener('blur', window['blurEvent']);
- }"""
- )
-
- await button.focus()
- assert focused
- assert not blurred
- assert await button.evaluate("button => document.activeElement === button")
-
- await button.blur()
- assert focused
- assert blurred
- assert not await button.evaluate("button => document.activeElement === button")
-
-
-async def test_locator_all_should_work(page: Page) -> None:
- await page.set_content("")
- texts = []
- for p in await page.locator("p").all():
- texts.append(await p.text_content())
- assert texts == ["A", "B", "C"]
-
-
-async def test_locator_click_timeout_error_should_contain_call_log(page: Page) -> None:
- with pytest.raises(Error) as exc_info:
- await page.get_by_role("button", name="Hello Python").click(timeout=42)
- formatted_exception = "".join(
- traceback.format_exception(type(exc_info.value), value=exc_info.value, tb=None)
- )
- assert "Locator.click: Timeout 42ms exceeded." in formatted_exception
- assert 'waiting for get_by_role("button", name="Hello Python")' in formatted_exception
- assert (
- "During handling of the above exception, another exception occurred"
- not in formatted_exception
- )
diff --git a/tests/async/test_navigation.py b/tests/async/test_navigation.py
deleted file mode 100644
index d23b77e..0000000
--- a/tests/async/test_navigation.py
+++ /dev/null
@@ -1,1057 +0,0 @@
-# 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 re
-import sys
-from pathlib import Path
-from typing import Any, List, Optional
-
-import pytest
-
-from playwright.async_api import (
- BrowserContext,
- Error,
- Page,
- Request,
- Response,
- Route,
- TimeoutError,
-)
-from tests.server import Server, TestServerRequest
-
-
-async def test_goto_should_work(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- assert page.url == server.EMPTY_PAGE
-
-
-async def test_goto_should_work_with_file_URL(page: Page, assetdir: Path) -> None:
- fileurl = (assetdir / "frames" / "two-frames.html").as_uri()
- await page.goto(fileurl)
- assert page.url.lower() == fileurl.lower()
- assert len(page.frames) == 3
-
-
-async def test_goto_should_use_http_for_no_protocol(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE[7:])
- assert page.url == server.EMPTY_PAGE
-
-
-async def test_goto_should_work_cross_process(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- assert page.url == server.EMPTY_PAGE
-
- url = server.CROSS_PROCESS_PREFIX + "/empty.html"
- request_frames = []
-
- def on_request(r: Request) -> None:
- if r.url == url:
- request_frames.append(r.frame)
-
- page.on("request", on_request)
-
- response = await page.goto(url)
- assert response
- assert page.url == url
- assert response.frame == page.main_frame
- assert request_frames[0] == page.main_frame
- assert response.url == url
-
-
-async def test_goto_should_capture_iframe_navigation_request(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- assert page.url == server.EMPTY_PAGE
-
- request_frames = []
-
- def on_request(r: Request) -> None:
- if r.url == server.PREFIX + "/frames/frame.html":
- request_frames.append(r.frame)
-
- page.on("request", on_request)
-
- response = await page.goto(server.PREFIX + "/frames/one-frame.html")
- assert response
- assert page.url == server.PREFIX + "/frames/one-frame.html"
- assert response.frame == page.main_frame
- assert response.url == server.PREFIX + "/frames/one-frame.html"
-
- assert len(page.frames) == 2
- assert request_frames[0] == page.frames[1]
-
-
-async def test_goto_should_capture_cross_process_iframe_navigation_request(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- assert page.url == server.EMPTY_PAGE
-
- request_frames = []
-
- def on_request(r: Request) -> None:
- if r.url == server.CROSS_PROCESS_PREFIX + "/frames/frame.html":
- request_frames.append(r.frame)
-
- page.on("request", on_request)
-
- response = await page.goto(server.CROSS_PROCESS_PREFIX + "/frames/one-frame.html")
- assert response
- assert page.url == server.CROSS_PROCESS_PREFIX + "/frames/one-frame.html"
- assert response.frame == page.main_frame
- assert response.url == server.CROSS_PROCESS_PREFIX + "/frames/one-frame.html"
-
- assert len(page.frames) == 2
- assert request_frames[0] == page.frames[1]
-
-
-async def test_goto_should_work_with_anchor_navigation(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- assert page.url == server.EMPTY_PAGE
- await page.goto(server.EMPTY_PAGE + "#foo")
- assert page.url == server.EMPTY_PAGE + "#foo"
- await page.goto(server.EMPTY_PAGE + "#bar")
- assert page.url == server.EMPTY_PAGE + "#bar"
-
-
-async def test_goto_should_work_with_redirects(page: Page, server: Server) -> None:
- server.set_redirect("/redirect/1.html", "/redirect/2.html")
- server.set_redirect("/redirect/2.html", "/empty.html")
- response = await page.goto(server.PREFIX + "/redirect/1.html")
- assert response
- assert response.status == 200
- assert page.url == server.EMPTY_PAGE
-
-
-async def test_goto_should_navigate_to_about_blank(page: Page, server: Server) -> None:
- response = await page.goto("about:blank")
- assert response is None
-
-
-async def test_goto_should_return_response_when_page_changes_its_url_after_load(
- page: Page, server: Server
-) -> None:
- response = await page.goto(server.PREFIX + "/historyapi.html")
- assert response
- assert response.status == 200
-
-
-@pytest.mark.skip_browser("firefox")
-async def test_goto_should_work_with_subframes_return_204(page: Page, server: Server) -> None:
- def handle(request: TestServerRequest) -> None:
- request.setResponseCode(204)
- request.finish()
-
- server.set_route("/frames/frame.html", handle)
-
- await page.goto(server.PREFIX + "/frames/one-frame.html")
-
-
-async def test_goto_should_fail_when_server_returns_204(
- page: Page, server: Server, is_chromium: bool, is_webkit: bool
-) -> None:
- # WebKit just loads an empty page.
- def handle(request: TestServerRequest) -> None:
- request.setResponseCode(204)
- request.finish()
-
- server.set_route("/empty.html", handle)
-
- with pytest.raises(Error) as exc_info:
- await page.goto(server.EMPTY_PAGE)
- assert exc_info.value
- if is_chromium:
- assert "net::ERR_ABORTED" in exc_info.value.message
- elif is_webkit:
- assert "Aborted: 204 No Content" in exc_info.value.message
- else:
- assert "NS_BINDING_ABORTED" in exc_info.value.message
-
-
-async def test_goto_should_navigate_to_empty_page_with_domcontentloaded(
- page: Page, server: Server
-) -> None:
- response = await page.goto(server.EMPTY_PAGE, wait_until="domcontentloaded")
- assert response
- assert response.status == 200
-
-
-async def test_goto_should_work_when_page_calls_history_api_in_beforeunload(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- await page.evaluate(
- """() => {
- window.addEventListener('beforeunload', () => history.replaceState(null, 'initial', window.location.href), false)
- }"""
- )
-
- response = await page.goto(server.PREFIX + "/grid.html")
- assert response
- assert response.status == 200
-
-
-async def test_goto_should_fail_when_navigating_to_bad_url(
- page: Page, is_chromium: bool, is_webkit: bool
-) -> None:
- with pytest.raises(Error) as exc_info:
- await page.goto("asdfasdf")
- if is_chromium or is_webkit:
- assert "Cannot navigate to invalid URL" in exc_info.value.message
- else:
- assert "Invalid url" in exc_info.value.message
-
-
-async def test_goto_should_fail_when_navigating_to_bad_ssl(
- page: Page, https_server: Server, browser_name: str
-) -> None:
- with pytest.raises(Error) as exc_info:
- await page.goto(https_server.EMPTY_PAGE)
- expect_ssl_error(exc_info.value.message, browser_name)
-
-
-async def test_goto_should_fail_when_navigating_to_bad_ssl_after_redirects(
- page: Page, server: Server, https_server: Server, browser_name: str
-) -> None:
- server.set_redirect("/redirect/1.html", "/redirect/2.html")
- server.set_redirect("/redirect/2.html", "/empty.html")
- with pytest.raises(Error) as exc_info:
- await page.goto(https_server.PREFIX + "/redirect/1.html")
- expect_ssl_error(exc_info.value.message, browser_name)
-
-
-async def test_goto_should_not_crash_when_navigating_to_bad_ssl_after_a_cross_origin_navigation(
- page: Page, server: Server, https_server: Server
-) -> None:
- await page.goto(server.CROSS_PROCESS_PREFIX + "/empty.html")
- with pytest.raises(Error):
- await page.goto(https_server.EMPTY_PAGE)
-
-
-async def test_goto_should_throw_if_networkidle2_is_passed_as_an_option(
- page: Page, server: Server
-) -> None:
- with pytest.raises(Error) as exc_info:
- await page.goto(server.EMPTY_PAGE, wait_until="networkidle2") # type: ignore
- assert (
- "wait_until: expected one of (load|domcontentloaded|networkidle|commit)"
- in exc_info.value.message
- )
-
-
-async def test_goto_should_fail_when_main_resources_failed_to_load(
- page: Page, is_chromium: bool, is_webkit: bool, is_win: bool
-) -> None:
- with pytest.raises(Error) as exc_info:
- await page.goto("http://localhost:44123/non-existing-url")
- if is_chromium:
- assert "net::ERR_CONNECTION_REFUSED" in exc_info.value.message
- elif is_webkit and is_win:
- assert "Couldn't connect to server" in exc_info.value.message
- elif is_webkit:
- assert "Could not connect" in exc_info.value.message
- else:
- assert "NS_ERROR_CONNECTION_REFUSED" in exc_info.value.message
-
-
-async def test_goto_should_fail_when_exceeding_maximum_navigation_timeout(
- page: Page, server: Server
-) -> None:
- # Hang for request to the empty.html
- server.set_route("/empty.html", lambda request: None)
- with pytest.raises(Error) as exc_info:
- await page.goto(server.PREFIX + "/empty.html", timeout=1)
- assert "Timeout 1ms exceeded" in exc_info.value.message
- assert server.PREFIX + "/empty.html" in exc_info.value.message
- assert isinstance(exc_info.value, TimeoutError)
-
-
-async def test_goto_should_fail_when_exceeding_default_maximum_navigation_timeout(
- page: Page, server: Server
-) -> None:
- # Hang for request to the empty.html
- server.set_route("/empty.html", lambda request: None)
- page.context.set_default_navigation_timeout(2)
- page.set_default_navigation_timeout(1)
- with pytest.raises(Error) as exc_info:
- await page.goto(server.PREFIX + "/empty.html")
- assert "Timeout 1ms exceeded" in exc_info.value.message
- assert server.PREFIX + "/empty.html" in exc_info.value.message
- assert isinstance(exc_info.value, TimeoutError)
-
-
-async def test_goto_should_fail_when_exceeding_browser_context_navigation_timeout(
- page: Page, server: Server
-) -> None:
- # Hang for request to the empty.html
- server.set_route("/empty.html", lambda request: None)
- page.context.set_default_navigation_timeout(2)
- with pytest.raises(Error) as exc_info:
- await page.goto(server.PREFIX + "/empty.html")
- assert "Timeout 2ms exceeded" in exc_info.value.message
- assert server.PREFIX + "/empty.html" in exc_info.value.message
- assert isinstance(exc_info.value, TimeoutError)
-
-
-async def test_goto_should_fail_when_exceeding_default_maximum_timeout(
- page: Page, server: Server
-) -> None:
- # Hang for request to the empty.html
- server.set_route("/empty.html", lambda request: None)
- page.context.set_default_timeout(2)
- page.set_default_timeout(1)
- with pytest.raises(Error) as exc_info:
- await page.goto(server.PREFIX + "/empty.html")
- assert "Timeout 1ms exceeded" in exc_info.value.message
- assert server.PREFIX + "/empty.html" in exc_info.value.message
- assert isinstance(exc_info.value, TimeoutError)
-
-
-async def test_goto_should_fail_when_exceeding_browser_context_timeout(
- page: Page, server: Server
-) -> None:
- # Hang for request to the empty.html
- server.set_route("/empty.html", lambda request: None)
- page.context.set_default_timeout(2)
- with pytest.raises(Error) as exc_info:
- await page.goto(server.PREFIX + "/empty.html")
- assert "Timeout 2ms exceeded" in exc_info.value.message
- assert server.PREFIX + "/empty.html" in exc_info.value.message
- assert isinstance(exc_info.value, TimeoutError)
-
-
-async def test_goto_should_prioritize_default_navigation_timeout_over_default_timeout(
- page: Page, server: Server
-) -> None:
- # Hang for request to the empty.html
- server.set_route("/empty.html", lambda request: None)
- page.set_default_timeout(0)
- page.set_default_navigation_timeout(1)
- with pytest.raises(Error) as exc_info:
- await page.goto(server.PREFIX + "/empty.html")
- assert "Timeout 1ms exceeded" in exc_info.value.message
- assert server.PREFIX + "/empty.html" in exc_info.value.message
- assert isinstance(exc_info.value, TimeoutError)
-
-
-async def test_goto_should_disable_timeout_when_its_set_to_0(page: Page, server: Server) -> None:
- loaded: List[bool] = []
- page.once("load", lambda _: loaded.append(True))
- await page.goto(server.PREFIX + "/grid.html", timeout=0, wait_until="load")
- assert loaded == [True]
-
-
-async def test_goto_should_work_when_navigating_to_valid_url(page: Page, server: Server) -> None:
- response = await page.goto(server.EMPTY_PAGE)
- assert response
- assert response.ok
-
-
-async def test_goto_should_work_when_navigating_to_data_url(page: Page, server: Server) -> None:
- response = await page.goto("data:text/html,hello")
- assert response is None
-
-
-async def test_goto_should_work_when_navigating_to_404(page: Page, server: Server) -> None:
- response = await page.goto(server.PREFIX + "/not-found")
- assert response
- assert response.ok is False
- assert response.status == 404
-
-
-async def test_goto_should_return_last_response_in_redirect_chain(
- page: Page, server: Server
-) -> None:
- server.set_redirect("/redirect/1.html", "/redirect/2.html")
- server.set_redirect("/redirect/2.html", "/redirect/3.html")
- server.set_redirect("/redirect/3.html", server.EMPTY_PAGE)
- response = await page.goto(server.PREFIX + "/redirect/1.html")
- assert response
- assert response.ok
- assert response.url == server.EMPTY_PAGE
-
-
-async def test_goto_should_navigate_to_data_url_and_not_fire_dataURL_requests(
- page: Page, server: Server
-) -> None:
- requests = []
- page.on("request", lambda request: requests.append(request))
- dataURL = "data:text/html,yo
"
- response = await page.goto(dataURL)
- assert response is None
- assert requests == []
-
-
-async def test_goto_should_navigate_to_url_with_hash_and_fire_requests_without_hash(
- page: Page, server: Server
-) -> None:
- requests = []
- page.on("request", lambda request: requests.append(request))
- response = await page.goto(server.EMPTY_PAGE + "#hash")
- assert response
- assert response.status == 200
- assert response.url == server.EMPTY_PAGE
- assert len(requests) == 1
- assert requests[0].url == server.EMPTY_PAGE
-
-
-async def test_goto_should_work_with_self_requesting_page(page: Page, server: Server) -> None:
- response = await page.goto(server.PREFIX + "/self-request.html")
- assert response
- assert response.status == 200
- assert "self-request.html" in response.url
-
-
-async def test_goto_should_fail_when_navigating_and_show_the_url_at_the_error_message(
- page: Page, https_server: Server
-) -> None:
- url = https_server.PREFIX + "/redirect/1.html"
- with pytest.raises(Error) as exc_info:
- await page.goto(url)
- assert url in exc_info.value.message
-
-
-async def test_goto_should_be_able_to_navigate_to_a_page_controlled_by_service_worker(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/serviceworkers/fetch/sw.html")
- await page.evaluate("window.activationPromise")
- await page.goto(server.PREFIX + "/serviceworkers/fetch/sw.html")
-
-
-async def test_goto_should_send_referer(page: Page, server: Server) -> None:
- [request1, request2, _] = await asyncio.gather(
- server.wait_for_request("/grid.html"),
- server.wait_for_request("/digits/1.png"),
- page.goto(server.PREFIX + "/grid.html", referer="http://google.com/"),
- )
- assert request1.getHeader("referer") == "http://google.com/"
- # Make sure subresources do not inherit referer.
- assert request2.getHeader("referer") == server.PREFIX + "/grid.html"
- assert page.url == server.PREFIX + "/grid.html"
-
-
-async def test_goto_should_reject_referer_option_when_set_extra_http_headers_provides_referer(
- page: Page, server: Server
-) -> None:
- await page.set_extra_http_headers({"referer": "http://microsoft.com/"})
- with pytest.raises(Error) as exc_info:
- await page.goto(server.PREFIX + "/grid.html", referer="http://google.com/")
- assert '"referer" is already specified as extra HTTP header' in exc_info.value.message
- assert server.PREFIX + "/grid.html" in exc_info.value.message
-
-
-async def test_goto_should_work_with_commit(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE, wait_until="commit")
- assert page.url == server.EMPTY_PAGE
-
-
-async def test_network_idle_should_navigate_to_empty_page_with_networkidle(
- page: Page, server: Server
-) -> None:
- response = await page.goto(server.EMPTY_PAGE, wait_until="networkidle")
- assert response
- assert response.status == 200
-
-
-async def test_wait_for_nav_should_work(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- async with page.expect_navigation() as response_info:
- await page.evaluate("url => window.location.href = url", server.PREFIX + "/grid.html")
- response = await response_info.value
- assert response.ok
- assert "grid.html" in response.url
-
-
-async def test_wait_for_nav_should_respect_timeout(page: Page, server: Server) -> None:
- with pytest.raises(Error) as exc_info:
- async with page.expect_navigation(url="**/frame.html", timeout=2500):
- await page.goto(server.EMPTY_PAGE)
- assert "Timeout 2500ms exceeded" in exc_info.value.message
-
-
-async def test_wait_for_nav_should_work_with_both_domcontentloaded_and_load(
- page: Page, server: Server
-) -> None:
- async with page.expect_navigation(wait_until="domcontentloaded"), page.expect_navigation(
- wait_until="load"
- ):
- await page.goto(server.PREFIX + "/one-style.html")
-
-
-async def test_wait_for_nav_should_work_with_clicking_on_anchor_links(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- await page.set_content('foobar ')
- async with page.expect_navigation() as response_info:
- await page.click("a")
- response = await response_info.value
- assert response is None
- assert page.url == server.EMPTY_PAGE + "#foobar"
-
-
-async def test_wait_for_nav_should_work_with_clicking_on_links_which_do_not_commit_navigation(
- page: Page, server: Server, https_server: Server, browser_name: str
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- await page.set_content(f"foobar ")
- with pytest.raises(Error) as exc_info:
- async with page.expect_navigation():
- await page.click("a")
- expect_ssl_error(exc_info.value.message, browser_name)
-
-
-async def test_wait_for_nav_should_work_with_history_push_state(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- await page.set_content(
- """
- SPA
-
- """
- )
- async with page.expect_navigation() as response_info:
- await page.click("a")
- response = await response_info.value
- assert response is None
- assert page.url == server.PREFIX + "/wow.html"
-
-
-async def test_wait_for_nav_should_work_with_history_replace_state(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- await page.set_content(
- """
- SPA
-
- """
- )
- async with page.expect_navigation() as response_info:
- await page.click("a")
- response = await response_info.value
- assert response is None
- assert page.url == server.PREFIX + "/replaced.html"
-
-
-async def test_wait_for_nav_should_work_with_dom_history_back_forward(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- await page.set_content(
- """
- back
- forward
-
- """
- )
- assert page.url == server.PREFIX + "/second.html"
- async with page.expect_navigation() as back_response_info:
- await page.click("a#back")
- back_response = await back_response_info.value
- assert back_response is None
- assert page.url == server.PREFIX + "/first.html"
- async with page.expect_navigation() as forward_response_info:
- await page.click("a#forward")
- forward_response = await forward_response_info.value
- assert forward_response is None
- assert page.url == server.PREFIX + "/second.html"
-
-
-@pytest.mark.skip_browser("webkit") # WebKit issues load event in some cases, but not always
-async def test_wait_for_nav_should_work_when_subframe_issues_window_stop(
- page: Page, server: Server, is_webkit: bool
-) -> None:
- server.set_route("/frames/style.css", lambda _: None)
- done = False
-
- async def nav_and_mark_done() -> None:
- nonlocal done
- await page.goto(server.PREFIX + "/frames/one-frame.html")
- done = True
-
- task = asyncio.create_task(nav_and_mark_done())
- await asyncio.sleep(0)
- async with page.expect_event("frameattached") as frame_info:
- pass
- frame = await frame_info.value
-
- async with page.expect_event("framenavigated", lambda f: f == frame):
- pass
- await frame.evaluate("() => window.stop()")
- await page.wait_for_timeout(2000) # give it some time to erroneously resolve
- assert done == (not is_webkit) # Chromium and Firefox issue load event in this case.
- if is_webkit:
- task.cancel()
-
-
-async def test_wait_for_nav_should_work_with_url_match(page: Page, server: Server) -> None:
- responses: List[Optional[Response]] = [None, None, None]
-
- async def wait_for_nav(url: Any, index: int) -> None:
- async with page.expect_navigation(url=url) as response_info:
- pass
- responses[index] = await response_info.value
-
- response0_promise = asyncio.create_task(wait_for_nav(re.compile(r"one-style\.html"), 0))
- response1_promise = asyncio.create_task(wait_for_nav(re.compile(r"\/frame.html"), 1))
- response2_promise = asyncio.create_task(wait_for_nav(lambda url: "foo=bar" in url, 2))
- assert responses == [None, None, None]
- await page.goto(server.EMPTY_PAGE)
- assert responses == [None, None, None]
- await page.goto(server.PREFIX + "/frame.html")
- assert responses[0] is None
- await response1_promise
- assert responses[1] is not None
- assert responses[2] is None
- await page.goto(server.PREFIX + "/one-style.html")
- await response0_promise
- assert responses[0] is not None
- assert responses[1] is not None
- assert responses[2] is None
- await page.goto(server.PREFIX + "/frame.html?foo=bar")
- await response2_promise
- assert responses[0] is not None
- assert responses[1] is not None
- assert responses[2] is not None
- await page.goto(server.PREFIX + "/empty.html")
- assert responses[0].url == server.PREFIX + "/one-style.html"
- assert responses[1].url == server.PREFIX + "/frame.html"
- assert responses[2].url == server.PREFIX + "/frame.html?foo=bar"
-
-
-async def test_wait_for_nav_should_work_with_url_match_for_same_document_navigations(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- async with page.expect_navigation(url=re.compile(r"third\.html")) as response_info:
- assert not response_info.is_done()
- await page.evaluate("history.pushState({}, '', '/first.html')")
- assert not response_info.is_done()
- await page.evaluate("history.pushState({}, '', '/second.html')")
- assert not response_info.is_done()
- await page.evaluate("history.pushState({}, '', '/third.html')")
- assert response_info.is_done()
-
-
-async def test_wait_for_nav_should_work_for_cross_process_navigations(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- url = server.CROSS_PROCESS_PREFIX + "/empty.html"
- async with page.expect_navigation(wait_until="domcontentloaded") as response_info:
- await page.goto(url)
- response = await response_info.value
- assert response.url == url
- assert page.url == url
- assert await page.evaluate("document.location.href") == url
-
-
-async def test_expect_navigation_should_work_for_cross_process_navigations(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- url = server.CROSS_PROCESS_PREFIX + "/empty.html"
- async with page.expect_navigation(wait_until="domcontentloaded") as response_info:
- goto_task = asyncio.create_task(page.goto(url))
- response = await response_info.value
- assert response.url == url
- assert page.url == url
- assert await page.evaluate("document.location.href") == url
- await goto_task
-
-
-async def test_wait_for_nav_should_work_with_commit(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- async with page.expect_navigation(wait_until="commit") as response_info:
- await page.evaluate("url => window.location.href = url", server.PREFIX + "/grid.html")
- response = await response_info.value
- assert response.ok
- assert "grid.html" in response.url
-
-
-async def test_wait_for_load_state_should_respect_timeout(page: Page, server: Server) -> None:
- requests = []
-
- def handler(request: Any) -> None:
- requests.append(request)
-
- server.set_route("/one-style.css", handler)
-
- await page.goto(server.PREFIX + "/one-style.html", wait_until="domcontentloaded")
- with pytest.raises(Error) as exc_info:
- await page.wait_for_load_state("load", timeout=1)
- assert "Timeout 1ms exceeded." in exc_info.value.message
-
-
-async def test_wait_for_load_state_should_resolve_immediately_if_loaded(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/one-style.html")
- await page.wait_for_load_state()
-
-
-async def test_wait_for_load_state_should_throw_for_bad_state(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/one-style.html")
- with pytest.raises(Error) as exc_info:
- await page.wait_for_load_state("bad") # type: ignore
- assert (
- "state: expected one of (load|domcontentloaded|networkidle|commit)"
- in exc_info.value.message
- )
-
-
-async def test_wait_for_load_state_should_resolve_immediately_if_load_state_matches(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
-
- requests = []
-
- def handler(request: Any) -> None:
- requests.append(request)
-
- server.set_route("/one-style.css", handler)
-
- await page.goto(server.PREFIX + "/one-style.html", wait_until="domcontentloaded")
- await page.wait_for_load_state("domcontentloaded")
-
-
-async def test_wait_for_load_state_networkidle(page: Page, server: Server) -> None:
- wait_for_network_idle_future = asyncio.create_task(page.wait_for_load_state("networkidle"))
- await page.goto(server.PREFIX + "/networkidle.html")
- await wait_for_network_idle_future
-
-
-async def test_wait_for_load_state_should_work_with_pages_that_have_loaded_before_being_connected_to(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- async with page.expect_popup() as popup_info:
- await page.evaluate("window._popup = window.open(document.location.href)")
-
- # The url is about:blank in FF.
- popup = await popup_info.value
- assert popup.url == server.EMPTY_PAGE
- await popup.wait_for_load_state()
- assert popup.url == server.EMPTY_PAGE
-
-
-async def test_wait_for_load_state_should_wait_for_load_state_of_empty_url_popup(
- page: Page, is_firefox: bool
-) -> None:
- ready_state = []
- async with page.expect_popup() as popup_info:
- ready_state.append(
- await page.evaluate(
- """() => {
- popup = window.open('')
- return popup.document.readyState
- }"""
- )
- )
-
- popup = await popup_info.value
- await popup.wait_for_load_state()
- assert ready_state == ["uninitialized"] if is_firefox else ["complete"]
- assert await popup.evaluate("() => document.readyState") == ready_state[0]
-
-
-async def test_wait_for_load_state_should_wait_for_load_state_of_about_blank_popup_(
- page: Page,
-) -> None:
- async with page.expect_popup() as popup_info:
- await page.evaluate("window.open('about:blank') && 1")
- popup = await popup_info.value
- await popup.wait_for_load_state()
- assert await popup.evaluate("document.readyState") == "complete"
-
-
-async def test_wait_for_load_state_should_wait_for_load_state_of_about_blank_popup_with_noopener(
- page: Page,
-) -> None:
- async with page.expect_popup() as popup_info:
- await page.evaluate("window.open('about:blank', null, 'noopener') && 1")
-
- popup = await popup_info.value
- await popup.wait_for_load_state()
- assert await popup.evaluate("document.readyState") == "complete"
-
-
-async def test_wait_for_load_state_should_wait_for_load_state_of_popup_with_network_url_(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- async with page.expect_popup() as popup_info:
- await page.evaluate("url => window.open(url) && 1", server.EMPTY_PAGE)
-
- popup = await popup_info.value
- await popup.wait_for_load_state()
- assert await popup.evaluate("document.readyState") == "complete"
-
-
-async def test_wait_for_load_state_should_wait_for_load_state_of_popup_with_network_url_and_noopener_(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- async with page.expect_popup() as popup_info:
- await page.evaluate("url => window.open(url, null, 'noopener') && 1", server.EMPTY_PAGE)
-
- popup = await popup_info.value
- await popup.wait_for_load_state()
- assert await popup.evaluate("document.readyState") == "complete"
-
-
-async def test_wait_for_load_state_should_work_with_clicking_target__blank(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- await page.set_content('yo ')
- async with page.expect_popup() as popup_info:
- await page.click("a")
- popup = await popup_info.value
- await popup.wait_for_load_state()
- assert await popup.evaluate("document.readyState") == "complete"
-
-
-async def test_wait_for_load_state_should_wait_for_load_state_of_new_page(
- context: BrowserContext,
-) -> None:
- async with context.expect_page() as page_info:
- await context.new_page()
- new_page = await page_info.value
- await new_page.wait_for_load_state()
- assert await new_page.evaluate("document.readyState") == "complete"
-
-
-async def test_wait_for_load_state_in_popup(context: BrowserContext, server: Server) -> None:
- page = await context.new_page()
- await page.goto(server.EMPTY_PAGE)
- css_requests = []
-
- def handle_request(request: TestServerRequest) -> None:
- css_requests.append(request)
- request.write(b"body {}")
- request.finish()
-
- server.set_route("/one-style.css", handle_request)
-
- async with page.expect_popup() as popup_info:
- await page.evaluate(
- "url => window.popup = window.open(url)", server.PREFIX + "/one-style.html"
- )
-
- popup = await popup_info.value
- await popup.wait_for_load_state()
- assert len(css_requests)
-
-
-async def test_go_back_should_work(page: Page, server: Server) -> None:
- assert await page.go_back() is None
-
- await page.goto(server.EMPTY_PAGE)
- await page.goto(server.PREFIX + "/grid.html")
-
- response = await page.go_back()
- assert response
- assert response.ok
- assert server.EMPTY_PAGE in response.url
-
- response = await page.go_forward()
- assert response
- assert response.ok
- assert "/grid.html" in response.url
-
- response = await page.go_forward()
- assert response is None
-
-
-async def test_go_back_should_work_with_history_api(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- await page.evaluate(
- """() => {
- history.pushState({}, '', '/first.html')
- history.pushState({}, '', '/second.html')
- }"""
- )
- assert page.url == server.PREFIX + "/second.html"
-
- await page.go_back()
- assert page.url == server.PREFIX + "/first.html"
- await page.go_back()
- assert page.url == server.EMPTY_PAGE
- await page.go_forward()
- assert page.url == server.PREFIX + "/first.html"
-
-
-async def test_frame_goto_should_navigate_subframes(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/frames/one-frame.html")
- assert "/frames/one-frame.html" in page.frames[0].url
- assert "/frames/frame.html" in page.frames[1].url
-
- response = await page.frames[1].goto(server.EMPTY_PAGE)
- assert response
- assert response.ok
- assert response.frame == page.frames[1]
-
-
-async def test_frame_goto_should_reject_when_frame_detaches(
- page: Page, server: Server, browser_name: str
-) -> None:
- await page.goto(server.PREFIX + "/frames/one-frame.html")
-
- server.set_route("/one-style.css", lambda _: None)
- wait_for_request_task = asyncio.create_task(server.wait_for_request("/one-style.css"))
- navigation_task = asyncio.create_task(page.frames[1].goto(server.PREFIX + "/one-style.html"))
- await wait_for_request_task
-
- await page.eval_on_selector("iframe", "frame => frame.remove()")
- with pytest.raises(Error) as exc_info:
- await navigation_task
- if browser_name == "chromium":
- assert "net::ERR_FAILED" in exc_info.value.message or (
- "frame was detached" in exc_info.value.message.lower()
- )
- else:
- assert "frame was detached" in exc_info.value.message.lower()
-
-
-async def test_frame_goto_should_continue_after_client_redirect(page: Page, server: Server) -> None:
- server.set_route("/frames/script.js", lambda _: None)
- url = server.PREFIX + "/frames/child-redirect.html"
-
- with pytest.raises(Error) as exc_info:
- await page.goto(url, timeout=5000, wait_until="networkidle")
-
- assert "Timeout 5000ms exceeded." in exc_info.value.message
- assert f'navigating to "{url}", waiting until "networkidle"' in exc_info.value.message
-
-
-async def test_frame_wait_for_nav_should_work(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/frames/one-frame.html")
- frame = page.frames[1]
- async with frame.expect_navigation() as response_info:
- await frame.evaluate("url => window.location.href = url", server.PREFIX + "/grid.html")
- response = await response_info.value
- assert response.ok
- assert "grid.html" in response.url
- assert response.frame == frame
- assert "/frames/one-frame.html" in page.url
-
-
-async def test_frame_wait_for_nav_should_fail_when_frame_detaches(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/frames/one-frame.html")
- frame = page.frames[1]
- server.set_route("/empty.html", lambda _: None)
- server.set_route("/one-style.css", lambda _: None)
- with pytest.raises(Error) as exc_info:
- async with frame.expect_navigation():
-
- async def after_it() -> None:
- await server.wait_for_request("/one-style.html")
- await page.eval_on_selector(
- "iframe", "frame => setTimeout(() => frame.remove(), 0)"
- )
-
- await asyncio.gather(
- page.eval_on_selector(
- "iframe",
- "frame => frame.contentWindow.location.href = '/one-style.html'",
- ),
- after_it(),
- )
- assert "frame was detached" in exc_info.value.message
-
-
-async def test_frame_wait_for_load_state_should_work(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/frames/one-frame.html")
- frame = page.frames[1]
-
- request_future: "asyncio.Future[Route]" = asyncio.Future()
- await page.route(
- server.PREFIX + "/one-style.css",
- lambda route, request: request_future.set_result(route),
- )
-
- await frame.goto(server.PREFIX + "/one-style.html", wait_until="domcontentloaded")
- request = await request_future
- load_task = asyncio.create_task(frame.wait_for_load_state())
- # give the promise a chance to resolve, even though it shouldn't
- await page.evaluate("1")
- assert not load_task.done()
- asyncio.create_task(request.continue_())
- await load_task
-
-
-async def test_reload_should_work(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- await page.evaluate("window._foo = 10")
- await page.reload()
- assert await page.evaluate("window._foo") is None
-
-
-async def test_reload_should_work_with_data_url(page: Page, server: Server) -> None:
- await page.goto("data:text/html,hello")
- assert "hello" in await page.content()
- assert await page.reload() is None
- assert "hello" in await page.content()
-
-
-async def test_should_work_with__blank_target(page: Page, server: Server) -> None:
- def handler(request: TestServerRequest) -> None:
- request.write(f'Click me '.encode())
- request.finish()
-
- server.set_route("/empty.html", handler)
-
- await page.goto(server.EMPTY_PAGE)
- await page.click('"Click me"')
-
-
-async def test_should_work_with_cross_process__blank_target(page: Page, server: Server) -> None:
- def handler(request: TestServerRequest) -> None:
- request.write(
- f'Click me '.encode()
- )
- request.finish()
-
- server.set_route("/empty.html", handler)
-
- await page.goto(server.EMPTY_PAGE)
- await page.click('"Click me"')
-
-
-def expect_ssl_error(error_message: str, browser_name: str) -> None:
- if browser_name == "chromium":
- assert "net::ERR_CERT_AUTHORITY_INVALID" in error_message
- elif browser_name == "webkit":
- if sys.platform == "darwin":
- assert "The certificate for this server is invalid" in error_message
- elif sys.platform == "win32":
- assert "SSL peer certificate or SSH remote key was not OK" in error_message
- else:
- assert "Unacceptable TLS certificate" in error_message
- else:
- assert "SSL_ERROR_UNKNOWN" in error_message
diff --git a/tests/async/test_network.py b/tests/async/test_network.py
deleted file mode 100644
index daf076e..0000000
--- a/tests/async/test_network.py
+++ /dev/null
@@ -1,879 +0,0 @@
-# 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 json
-from asyncio import Future
-from pathlib import Path
-from typing import Dict, List, Optional, Union
-
-import pytest
-from flaky import flaky
-from twisted.web import http
-
-from playwright.async_api import Browser, Error, Page, Request, Response, Route
-from tests.server import Server, TestServerRequest
-
-from .utils import Utils
-
-
-def adjust_server_headers(headers: Dict[str, str], browser_name: str) -> Dict[str, str]:
- if browser_name != "firefox":
- return headers
- headers = headers.copy()
- headers.pop("priority", None)
- return headers
-
-
-async def test_request_fulfill(page: Page, server: Server) -> None:
- async def handle_request(route: Route, request: Request) -> None:
- headers = await route.request.all_headers()
- assert headers["accept"]
- assert route.request == request
- assert repr(route) == f""
- assert "empty.html" in request.url
- assert request.headers["user-agent"]
- assert request.method == "GET"
- assert request.post_data is None
- assert request.is_navigation_request()
- assert request.resource_type == "document"
- assert request.frame == page.main_frame
- assert request.frame.url == "about:blank"
- assert repr(request) == f""
- await route.fulfill(body="Text")
-
- await page.route(
- "**/empty.html",
- lambda route, request: asyncio.create_task(handle_request(route, request)),
- )
-
- response = await page.goto(server.EMPTY_PAGE)
- assert response
-
- assert response.ok
- assert repr(response) == f""
- assert await response.text() == "Text"
-
-
-async def test_request_continue(page: Page, server: Server) -> None:
- async def handle_request(route: Route, request: Request, intercepted: List[bool]) -> None:
- intercepted.append(True)
- await route.continue_()
-
- intercepted: List[bool] = []
- await page.route(
- "**/*",
- lambda route, request: asyncio.create_task(handle_request(route, request, intercepted)),
- )
-
- response = await page.goto(server.EMPTY_PAGE)
- assert response
- assert response.ok
- assert intercepted == [True]
- assert await page.title() == ""
-
-
-async def test_page_events_request_should_fire_for_navigation_requests(
- page: Page, server: Server
-) -> None:
- requests = []
- page.on("request", lambda r: requests.append(r))
- await page.goto(server.EMPTY_PAGE)
- assert len(requests) == 1
-
-
-async def test_page_events_request_should_accept_method(page: Page, server: Server) -> None:
- class Log:
- def __init__(self) -> None:
- self.requests: List[Request] = []
-
- def handle(self, request: Request) -> None:
- self.requests.append(request)
-
- log = Log()
- page.on("request", log.handle)
- await page.goto(server.EMPTY_PAGE)
- assert len(log.requests) == 1
-
-
-async def test_page_events_request_should_fire_for_iframes(
- page: Page, server: Server, utils: Utils
-) -> None:
- requests = []
- page.on("request", lambda r: requests.append(r))
- await page.goto(server.EMPTY_PAGE)
- await utils.attach_frame(page, "frame1", server.EMPTY_PAGE)
- assert len(requests) == 2
-
-
-async def test_page_events_request_should_fire_for_fetches(page: Page, server: Server) -> None:
- requests = []
- page.on("request", lambda r: requests.append(r))
- await page.goto(server.EMPTY_PAGE)
- await page.evaluate('() => fetch("/empty.html")')
- assert len(requests) == 2
-
-
-async def test_page_events_request_should_report_requests_and_responses_handled_by_service_worker(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/serviceworkers/fetchdummy/sw.html")
- await page.evaluate("() => window.activationPromise")
- sw_response = None
- async with page.expect_request("**/*") as request_info:
- sw_response = await page.evaluate('() => fetchDummy("foo")')
- request = await request_info.value
- assert sw_response == "responseFromServiceWorker:foo"
- assert request.url == server.PREFIX + "/serviceworkers/fetchdummy/foo"
- response = await request.response()
- assert response
- assert response.url == server.PREFIX + "/serviceworkers/fetchdummy/foo"
- assert await response.text() == "responseFromServiceWorker:foo"
-
-
-async def test_request_frame_should_work_for_main_frame_navigation_request(
- page: Page, server: Server
-) -> None:
- requests = []
- page.on("request", lambda r: requests.append(r))
- await page.goto(server.EMPTY_PAGE)
- assert len(requests) == 1
- assert requests[0].frame == page.main_frame
-
-
-async def test_request_frame_should_work_for_subframe_navigation_request(
- page: Page, server: Server, utils: Utils
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- requests = []
- page.on("request", lambda r: requests.append(r))
- await utils.attach_frame(page, "frame1", server.EMPTY_PAGE)
- assert len(requests) == 1
- assert requests[0].frame == page.frames[1]
-
-
-async def test_request_frame_should_work_for_fetch_requests(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- requests: List[Request] = []
- page.on("request", lambda r: requests.append(r))
- await page.evaluate('() => fetch("/digits/1.png")')
- requests = [r for r in requests if "favicon" not in r.url]
- assert len(requests) == 1
- assert requests[0].frame == page.main_frame
-
-
-async def test_request_headers_should_work(
- page: Page, server: Server, is_chromium: bool, is_firefox: bool, is_webkit: bool
-) -> None:
- response = await page.goto(server.EMPTY_PAGE)
- assert response
- if is_chromium:
- assert "Chrome" in response.request.headers["user-agent"]
- elif is_firefox:
- assert "Firefox" in response.request.headers["user-agent"]
- elif is_webkit:
- assert "WebKit" in response.request.headers["user-agent"]
-
-
-async def test_request_headers_should_get_the_same_headers_as_the_server(
- page: Page,
- server: Server,
- is_webkit: bool,
- is_win: bool,
- browser_name: str,
-) -> None:
- if is_webkit and is_win:
- pytest.xfail("Curl does not show accept-encoding and accept-language")
- server_request_headers_future: Future[Dict[str, str]] = asyncio.Future()
-
- def handle(request: http.Request) -> None:
- normalized_headers = {
- key.decode().lower(): value[0].decode()
- for key, value in request.requestHeaders.getAllRawHeaders()
- }
- server_request_headers_future.set_result(normalized_headers)
- request.write(b"done")
- request.finish()
-
- server.set_route("/empty.html", handle)
- response = await page.goto(server.EMPTY_PAGE)
- assert response
- server_headers = adjust_server_headers(await server_request_headers_future, browser_name)
- assert await response.request.all_headers() == server_headers
-
-
-async def test_request_headers_should_get_the_same_headers_as_the_server_cors(
- page: Page, server: Server, is_webkit: bool, is_win: bool, browser_name: str
-) -> None:
- if is_webkit and is_win:
- pytest.xfail("Curl does not show accept-encoding and accept-language")
- await page.goto(server.PREFIX + "/empty.html")
- server_request_headers_future: Future[Dict[str, str]] = asyncio.Future()
-
- def handle_something(request: http.Request) -> None:
- normalized_headers = {
- key.decode().lower(): value[0].decode()
- for key, value in request.requestHeaders.getAllRawHeaders()
- }
- server_request_headers_future.set_result(normalized_headers)
- request.setHeader("Access-Control-Allow-Origin", "*")
- request.write(b"done")
- request.finish()
-
- server.set_route("/something", handle_something)
-
- text = None
- async with page.expect_request("**/*") as request_info:
- text = await page.evaluate(
- """async url => {
- const data = await fetch(url);
- return data.text();
- }""",
- server.CROSS_PROCESS_PREFIX + "/something",
- )
- request = await request_info.value
- assert text == "done"
- server_headers = adjust_server_headers(await server_request_headers_future, browser_name)
- assert await request.all_headers() == server_headers
-
-
-async def test_should_report_request_headers_array(
- page: Page, server: Server, is_win: bool, browser_name: str
-) -> None:
- if is_win and browser_name == "webkit":
- pytest.skip("libcurl does not support non-set-cookie multivalue headers")
- expected_headers = []
-
- def handle(request: http.Request) -> None:
- for name, values in request.requestHeaders.getAllRawHeaders():
- for value in values:
- if browser_name == "firefox" and name.decode().lower() == "priority":
- continue
- expected_headers.append({"name": name.decode().lower(), "value": value.decode()})
- request.finish()
-
- server.set_route("/headers", handle)
- await page.goto(server.EMPTY_PAGE)
- async with page.expect_request("*/**") as request_info:
- await page.evaluate(
- """() => fetch('/headers', {
- headers: [
- ['header-a', 'value-a'],
- ['header-b', 'value-b'],
- ['header-a', 'value-a-1'],
- ['header-a', 'value-a-2'],
- ]
- })
- """
- )
- request = await request_info.value
- sorted_pw_request_headers = sorted(
- list(
- map(
- lambda header: {
- "name": header["name"].lower(),
- "value": header["value"],
- },
- await request.headers_array(),
- )
- ),
- key=lambda header: header["name"],
- )
- sorted_expected_headers = sorted(expected_headers, key=lambda header: header["name"])
- assert sorted_pw_request_headers == sorted_expected_headers
- assert await request.header_value("Header-A") == "value-a, value-a-1, value-a-2"
- assert await request.header_value("not-there") is None
-
-
-async def test_should_report_response_headers_array(
- page: Page, server: Server, is_win: bool, browser_name: str
-) -> None:
- if is_win and browser_name == "webkit":
- pytest.skip("libcurl does not support non-set-cookie multivalue headers")
- expected_headers = {
- "header-a": ["value-a", "value-a-1", "value-a-2"],
- "header-b": ["value-b"],
- "set-cookie": ["a=b", "c=d"],
- }
-
- def handle(request: http.Request) -> None:
- for key in expected_headers:
- for value in expected_headers[key]:
- request.responseHeaders.addRawHeader(key, value)
- request.finish()
-
- server.set_route("/headers", handle)
- await page.goto(server.EMPTY_PAGE)
- async with page.expect_response("*/**") as response_info:
- await page.evaluate(
- """() => fetch('/headers')
- """
- )
- response = await response_info.value
- actual_headers: Dict[str, List[str]] = {}
- for header in await response.headers_array():
- name = header["name"].lower()
- value = header["value"]
- if not actual_headers.get(name):
- actual_headers[name] = []
- actual_headers[name].append(value)
-
- for key in ["Keep-Alive", "Connection", "Date", "Transfer-Encoding"]:
- if key in actual_headers:
- actual_headers.pop(key)
- if key.lower() in actual_headers:
- actual_headers.pop(key.lower())
- assert actual_headers == expected_headers
- assert await response.header_value("not-there") is None
- assert await response.header_value("set-cookie") == "a=b\nc=d"
- assert await response.header_value("header-a") == "value-a, value-a-1, value-a-2"
- assert await response.header_values("set-cookie") == ["a=b", "c=d"]
-
-
-async def test_response_headers_should_work(page: Page, server: Server) -> None:
- server.set_route("/empty.html", lambda r: (r.setHeader("foo", "bar"), r.finish()))
-
- response = await page.goto(server.EMPTY_PAGE)
- assert response
- assert response.headers["foo"] == "bar"
- assert (await response.all_headers())["foo"] == "bar"
-
-
-async def test_request_post_data_should_work(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- server.set_route("/post", lambda r: r.finish())
- requests = []
- page.on("request", lambda r: requests.append(r))
- await page.evaluate(
- '() => fetch("./post", { method: "POST", body: JSON.stringify({foo: "bar"})})'
- )
- assert len(requests) == 1
- assert requests[0].post_data == '{"foo":"bar"}'
-
-
-async def test_request_post_data__should_be_undefined_when_there_is_no_post_data(
- page: Page, server: Server
-) -> None:
- response = await page.goto(server.EMPTY_PAGE)
- assert response
- assert response.request.post_data is None
-
-
-async def test_should_parse_the_json_post_data(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- server.set_route("/post", lambda req: req.finish())
- requests = []
- page.on("request", lambda r: requests.append(r))
- await page.evaluate(
- """() => fetch('./post', { method: 'POST', body: JSON.stringify({ foo: 'bar' }) })"""
- )
- assert len(requests) == 1
- assert requests[0].post_data_json == {"foo": "bar"}
-
-
-async def test_should_parse_the_data_if_content_type_is_form_urlencoded(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- server.set_route("/post", lambda req: req.finish())
- requests = []
- page.on("request", lambda r: requests.append(r))
- await page.set_content(
- """"""
- )
- await page.click("input[type=submit]")
- assert len(requests) == 1
- assert requests[0].post_data_json == {"foo": "bar", "baz": "123"}
-
-
-async def test_should_be_undefined_when_there_is_no_post_data(page: Page, server: Server) -> None:
- response = await page.goto(server.EMPTY_PAGE)
- assert response
- assert response.request.post_data_json is None
-
-
-async def test_should_return_post_data_without_content_type(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- async with page.expect_request("**/*") as request_info:
- await page.evaluate(
- """({url}) => {
- const request = new Request(url, {
- method: 'POST',
- body: JSON.stringify({ value: 42 }),
- });
- request.headers.set('content-type', '');
- return fetch(request);
- }""",
- {"url": server.PREFIX + "/title.html"},
- )
- request = await request_info.value
- assert request.post_data_json == {"value": 42}
-
-
-async def test_should_throw_on_invalid_json_in_post_data(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- async with page.expect_request("**/*") as request_info:
- await page.evaluate(
- """({url}) => {
- const request = new Request(url, {
- method: 'POST',
- body: '',
- });
- request.headers.set('content-type', '');
- return fetch(request);
- }""",
- {"url": server.PREFIX + "/title.html"},
- )
- request = await request_info.value
- with pytest.raises(Error) as exc_info:
- print(request.post_data_json)
- assert "POST data is not a valid JSON object: " in str(exc_info.value)
-
-
-async def test_should_work_with_binary_post_data(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- server.set_route("/post", lambda req: req.finish())
- requests = []
- page.on("request", lambda r: requests.append(r))
- await page.evaluate(
- """async () => {
- await fetch('./post', { method: 'POST', body: new Uint8Array(Array.from(Array(256).keys())) })
- }"""
- )
- assert len(requests) == 1
- buffer = requests[0].post_data_buffer
- assert len(buffer) == 256
- for i in range(256):
- assert buffer[i] == i
-
-
-async def test_should_work_with_binary_post_data_and_interception(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- server.set_route("/post", lambda req: req.finish())
- requests = []
- await page.route("/post", lambda route: asyncio.ensure_future(route.continue_()))
- page.on("request", lambda r: requests.append(r))
- await page.evaluate(
- """async () => {
- await fetch('./post', { method: 'POST', body: new Uint8Array(Array.from(Array(256).keys())) })
- }"""
- )
- assert len(requests) == 1
- buffer = requests[0].post_data_buffer
- assert len(buffer) == 256
- for i in range(256):
- assert buffer[i] == i
-
-
-async def test_response_text_should_work(page: Page, server: Server) -> None:
- response = await page.goto(server.PREFIX + "/simple.json")
- assert response
- assert await response.text() == '{"foo": "bar"}\n'
-
-
-async def test_response_text_should_return_uncompressed_text(page: Page, server: Server) -> None:
- server.enable_gzip("/simple.json")
- response = await page.goto(server.PREFIX + "/simple.json")
- assert response
- assert response.headers["content-encoding"] == "gzip"
- assert await response.text() == '{"foo": "bar"}\n'
-
-
-async def test_response_text_should_throw_when_requesting_body_of_redirected_response(
- page: Page, server: Server
-) -> None:
- server.set_redirect("/foo.html", "/empty.html")
- response = await page.goto(server.PREFIX + "/foo.html")
- assert response
- redirected_from = response.request.redirected_from
- assert redirected_from
- redirected = await redirected_from.response()
- assert redirected
- assert redirected.status == 302
- error: Optional[Error] = None
- try:
- await redirected.text()
- except Error as exc:
- error = exc
- assert error
- assert "Response body is unavailable for redirect responses" in error.message
-
-
-async def test_response_json_should_work(page: Page, server: Server) -> None:
- response = await page.goto(server.PREFIX + "/simple.json")
- assert response
- assert await response.json() == {"foo": "bar"}
-
-
-async def test_response_body_should_work(page: Page, server: Server, assetdir: Path) -> None:
- response = await page.goto(server.PREFIX + "/pptr.png")
- assert response
- with open(
- assetdir / "pptr.png",
- "rb",
- ) as fd:
- assert fd.read() == await response.body()
-
-
-async def test_response_body_should_work_with_compression(
- page: Page, server: Server, assetdir: Path
-) -> None:
- server.enable_gzip("/pptr.png")
- response = await page.goto(server.PREFIX + "/pptr.png")
- assert response
- with open(
- assetdir / "pptr.png",
- "rb",
- ) as fd:
- assert fd.read() == await response.body()
-
-
-async def test_response_status_text_should_work(page: Page, server: Server) -> None:
- server.set_route("/cool", lambda r: (r.setResponseCode(200, b"cool!"), r.finish()))
-
- response = await page.goto(server.PREFIX + "/cool")
- assert response
- assert response.status_text == "cool!"
-
-
-async def test_request_resource_type_should_return_event_source(page: Page, server: Server) -> None:
- SSE_MESSAGE = {"foo": "bar"}
- # 1. Setup server-sent events on server that immediately sends a message to the client.
- server.set_route(
- "/sse",
- lambda r: (
- r.setHeader("Content-Type", "text/event-stream"),
- r.setHeader("Connection", "keep-alive"),
- r.setHeader("Cache-Control", "no-cache"),
- r.setResponseCode(200),
- r.write(f"data: {json.dumps(SSE_MESSAGE)}\n\n".encode()),
- r.finish(),
- ),
- )
-
- # 2. Subscribe to page request events.
- await page.goto(server.EMPTY_PAGE)
- requests = []
- page.on("request", lambda r: requests.append(r))
- # 3. Connect to EventSource in browser and return first message.
- assert (
- await page.evaluate(
- """() => {
- const eventSource = new EventSource('/sse');
- return new Promise(resolve => {
- eventSource.onmessage = e => resolve(JSON.parse(e.data));
- });
- }"""
- )
- == SSE_MESSAGE
- )
- assert requests[0].resource_type == "eventsource"
-
-
-async def test_network_events_request(page: Page, server: Server) -> None:
- requests = []
- page.on("request", lambda r: requests.append(r))
- await page.goto(server.EMPTY_PAGE)
- assert len(requests) == 1
- assert requests[0].url == server.EMPTY_PAGE
- assert requests[0].resource_type == "document"
- assert requests[0].method == "GET"
- assert await requests[0].response()
- assert requests[0].frame == page.main_frame
- assert requests[0].frame.url == server.EMPTY_PAGE
-
-
-async def test_network_events_response(page: Page, server: Server) -> None:
- responses = []
- page.on("response", lambda r: responses.append(r))
- await page.goto(server.EMPTY_PAGE)
- assert len(responses) == 1
- assert responses[0].url == server.EMPTY_PAGE
- assert responses[0].status == 200
- assert responses[0].ok
- assert responses[0].request
-
-
-async def test_network_events_request_failed(
- page: Page,
- server: Server,
- is_chromium: bool,
- is_webkit: bool,
- is_mac: bool,
- is_win: bool,
-) -> None:
- def handle_request(request: TestServerRequest) -> None:
- request.setHeader("Content-Type", "text/css")
- request.loseConnection()
-
- server.set_route("/one-style.css", handle_request)
-
- failed_requests = []
- page.on("requestfailed", lambda request: failed_requests.append(request))
- await page.goto(server.PREFIX + "/one-style.html")
- # 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"
- if is_chromium:
- assert failed_requests[0].failure == "net::ERR_EMPTY_RESPONSE"
- elif is_webkit:
- if is_mac:
- assert failed_requests[0].failure == "The network connection was lost."
- elif is_win:
- assert failed_requests[0].failure == "Server returned nothing (no headers, no data)"
- else:
- assert failed_requests[0].failure in [
- "Message Corrupt",
- "Connection terminated unexpectedly",
- ]
- else:
- assert failed_requests[0].failure == "NS_ERROR_NET_RESET"
- assert failed_requests[0].frame
-
-
-async def test_network_events_request_finished(page: Page, server: Server) -> None:
- async with page.expect_event("requestfinished") as event_info:
- await page.goto(server.EMPTY_PAGE)
- request = await event_info.value
- assert request.url == server.EMPTY_PAGE
- assert await request.response()
- assert request.frame == page.main_frame
- assert request.frame.url == server.EMPTY_PAGE
-
-
-async def test_network_events_should_fire_events_in_proper_order(
- page: Page, server: Server
-) -> None:
- events = []
- page.on("request", lambda request: events.append("request"))
- page.on("response", lambda response: events.append("response"))
- response = await page.goto(server.EMPTY_PAGE)
- assert response
- await response.finished()
- events.append("requestfinished")
- assert events == ["request", "response", "requestfinished"]
-
-
-async def test_network_events_should_support_redirects(page: Page, server: Server) -> None:
- FOO_URL = server.PREFIX + "/foo.html"
- events: Dict[str, List[Union[str, int]]] = {}
- events[FOO_URL] = []
- events[server.EMPTY_PAGE] = []
-
- def _handle_on_request(request: Request) -> None:
- events[request.url].append(request.method)
-
- page.on("request", _handle_on_request)
-
- def _handle_on_response(response: Response) -> None:
- events[response.url].append(response.status)
-
- page.on("response", _handle_on_response)
-
- def _handle_on_requestfinished(request: Request) -> None:
- events[request.url].append("DONE")
-
- page.on("requestfinished", _handle_on_requestfinished)
-
- def _handle_on_requestfailed(request: Request) -> None:
- events[request.url].append("FAIL")
-
- page.on("requestfailed", _handle_on_requestfailed)
- server.set_redirect("/foo.html", "/empty.html")
- response = await page.goto(FOO_URL)
- assert response
- await response.finished()
- expected = {}
- expected[FOO_URL] = ["GET", 302, "DONE"]
- expected[server.EMPTY_PAGE] = ["GET", 200, "DONE"]
- assert events == expected
- redirected_from = response.request.redirected_from
- assert redirected_from
- assert "/foo.html" in redirected_from.url
- assert redirected_from.redirected_from is None
- assert redirected_from.redirected_to == response.request
-
-
-async def test_request_is_navigation_request_should_work(page: Page, server: Server) -> None:
- requests: Dict[str, Request] = {}
-
- def handle_request(request: Request) -> None:
- requests[request.url.split("/").pop()] = request
-
- page.on("request", handle_request)
- server.set_redirect("/rrredirect", "/frames/one-frame.html")
- await page.goto(server.PREFIX + "/rrredirect")
- assert requests["rrredirect"].is_navigation_request()
- assert requests["one-frame.html"].is_navigation_request()
- assert requests["frame.html"].is_navigation_request()
- assert requests["script.js"].is_navigation_request() is False
- assert requests["style.css"].is_navigation_request() is False
-
-
-async def test_request_is_navigation_request_should_work_when_navigating_to_image(
- page: Page, server: Server
-) -> None:
- requests = []
- page.on("request", lambda r: requests.append(r))
- await page.goto(server.PREFIX + "/pptr.png")
- assert requests[0].is_navigation_request()
-
-
-async def test_set_extra_http_headers_should_work(page: Page, server: Server) -> None:
- await page.set_extra_http_headers({"foo": "bar"})
-
- request = (
- await asyncio.gather(
- server.wait_for_request("/empty.html"),
- page.goto(server.EMPTY_PAGE),
- )
- )[0]
- assert request.getHeader("foo") == "bar"
-
-
-async def test_set_extra_http_headers_should_work_with_redirects(
- page: Page, server: Server
-) -> None:
- server.set_redirect("/foo.html", "/empty.html")
- await page.set_extra_http_headers({"foo": "bar"})
-
- request = (
- await asyncio.gather(
- server.wait_for_request("/empty.html"),
- page.goto(server.PREFIX + "/foo.html"),
- )
- )[0]
- assert request.getHeader("foo") == "bar"
-
-
-async def test_set_extra_http_headers_should_work_with_extra_headers_from_browser_context(
- browser: Browser, server: Server
-) -> None:
- context = await browser.new_context()
- await context.set_extra_http_headers({"foo": "bar"})
-
- page = await context.new_page()
- request = (
- await asyncio.gather(
- server.wait_for_request("/empty.html"),
- page.goto(server.EMPTY_PAGE),
- )
- )[0]
- await context.close()
- assert request.getHeader("foo") == "bar"
-
-
-@flaky # Flaky upstream https://devops.aslushnikov.com/flakiness2.html#filter_spec=should+override+extra+headers+from+browser+context&test_parameter_filters=%5B%5B%22browserName%22%2C%5B%5B%22webkit%22%2C%22include%22%5D%5D%5D%2C%5B%22video%22%2C%5B%5Btrue%2C%22exclude%22%5D%5D%5D%2C%5B%22platform%22%2C%5B%5B%22Windows%22%2C%22include%22%5D%5D%5D%5D
-async def test_set_extra_http_headers_should_override_extra_headers_from_browser_context(
- browser: Browser, server: Server
-) -> None:
- context = await browser.new_context(extra_http_headers={"fOo": "bAr", "baR": "foO"})
-
- page = await context.new_page()
- await page.set_extra_http_headers({"Foo": "Bar"})
-
- request = (
- await asyncio.gather(
- server.wait_for_request("/empty.html"),
- page.goto(server.EMPTY_PAGE),
- )
- )[0]
- await context.close()
- assert request.getHeader("foo") == "Bar"
- assert request.getHeader("bar") == "foO"
-
-
-async def test_set_extra_http_headers_should_throw_for_non_string_header_values(
- page: Page,
-) -> None:
- error: Optional[Error] = None
- try:
- await page.set_extra_http_headers({"foo": 1}) # type: ignore
- except Error as exc:
- error = exc
- assert error
- assert (
- error.message
- == "Page.set_extra_http_headers: headers[0].value: expected string, got number"
- )
-
-
-async def test_response_server_addr(page: Page, server: Server) -> None:
- response = await page.goto(f"http://127.0.0.1:{server.PORT}")
- assert response
- server_addr = await response.server_addr()
- assert server_addr
- assert server_addr["port"] == server.PORT
- assert server_addr["ipAddress"] in ["127.0.0.1", "::1"]
-
-
-async def test_response_security_details(
- browser: Browser,
- https_server: Server,
- browser_name: str,
- is_win: bool,
- is_linux: bool,
-) -> None:
- if (browser_name == "webkit" and is_linux) or (browser_name == "webkit" and is_win):
- pytest.skip("https://github.com/microsoft/playwright/issues/6759")
- page = await browser.new_page(ignore_https_errors=True)
- response = await page.goto(https_server.EMPTY_PAGE)
- assert response
- await response.finished()
- security_details = await response.security_details()
- assert security_details
- if browser_name == "webkit" and is_win:
- assert security_details == {
- "subjectName": "puppeteer-tests",
- "validFrom": 1550084863,
- "validTo": -1,
- }
- elif browser_name == "webkit":
- assert security_details == {
- "protocol": "TLS 1.3",
- "subjectName": "puppeteer-tests",
- "validFrom": 1550084863,
- "validTo": 33086084863,
- }
- else:
- assert security_details == {
- "issuer": "puppeteer-tests",
- "protocol": "TLS 1.3",
- "subjectName": "puppeteer-tests",
- "validFrom": 1550084863,
- "validTo": 33086084863,
- }
- await page.close()
-
-
-async def test_response_security_details_none_without_https(page: Page, server: Server) -> None:
- response = await page.goto(server.EMPTY_PAGE)
- assert response
- security_details = await response.security_details()
- assert security_details is None
-
-
-async def test_should_report_if_request_was_from_service_worker(page: Page, server: Server) -> None:
- response = await page.goto(server.PREFIX + "/serviceworkers/fetch/sw.html")
- assert response
- assert not response.from_service_worker
- await page.evaluate("() => window.activationPromise")
- async with page.expect_response("**/example.txt") as response_info:
- await page.evaluate("() => fetch('/example.txt')")
- response = await response_info.value
- assert response.from_service_worker
diff --git a/tests/async/test_page.py b/tests/async/test_page.py
deleted file mode 100644
index 3fc2d78..0000000
--- a/tests/async/test_page.py
+++ /dev/null
@@ -1,1358 +0,0 @@
-# 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 os
-import re
-from pathlib import Path
-from typing import Dict, List, Optional
-
-import pytest
-
-from playwright.async_api import (
- BrowserContext,
- Error,
- JSHandle,
- Page,
- Route,
- TimeoutError,
-)
-from tests.server import Server, TestServerRequest
-from tests.utils import TARGET_CLOSED_ERROR_MESSAGE, must
-
-
-async def test_close_should_reject_all_promises(context: BrowserContext) -> None:
- new_page = await context.new_page()
- with pytest.raises(Error) as exc_info:
- await asyncio.gather(new_page.evaluate("() => new Promise(r => {})"), new_page.close())
- assert " closed" in exc_info.value.message
-
-
-async def test_closed_should_not_visible_in_context_pages(
- context: BrowserContext,
-) -> None:
- page = await context.new_page()
- assert page in context.pages
- await page.close()
- assert page not in context.pages
-
-
-async def test_close_should_run_beforeunload_if_asked_for(
- context: BrowserContext, server: Server, is_chromium: bool, is_webkit: bool
-) -> None:
- page = await context.new_page()
- await page.goto(server.PREFIX + "/beforeunload.html")
- # We have to interact with a page so that 'beforeunload' handlers
- # fire.
- await page.click("body")
-
- async with page.expect_event("dialog") as dialog_info:
- await page.close(run_before_unload=True)
- dialog = await dialog_info.value
-
- assert dialog.type == "beforeunload"
- assert dialog.default_value == ""
- if is_chromium:
- assert dialog.message == ""
- elif is_webkit:
- assert dialog.message == "Leave?"
- else:
- assert "This page is asking you to confirm that you want to leave" in dialog.message
- async with page.expect_event("close"):
- await dialog.accept()
-
-
-async def test_close_should_not_run_beforeunload_by_default(
- context: BrowserContext, server: Server
-) -> None:
- page = await context.new_page()
- await page.goto(server.PREFIX + "/beforeunload.html")
- # We have to interact with a page so that 'beforeunload' handlers
- # fire.
- await page.click("body")
- await page.close()
-
-
-async def test_should_be_able_to_navigate_away_from_page_with_before_unload(
- server: Server, page: Page
-) -> None:
- await page.goto(server.PREFIX + "/beforeunload.html")
- # We have to interact with a page so that 'beforeunload' handlers
- # fire.
- await page.click("body")
- await page.goto(server.EMPTY_PAGE)
-
-
-async def test_close_should_set_the_page_close_state(context: BrowserContext) -> None:
- page = await context.new_page()
- assert page.is_closed() is False
- await page.close()
- assert page.is_closed()
-
-
-async def test_close_should_terminate_network_waiters(
- context: BrowserContext, server: Server
-) -> None:
- page = await context.new_page()
-
- async def wait_for_request() -> Error:
- with pytest.raises(Error) as exc_info:
- async with page.expect_request(server.EMPTY_PAGE):
- pass
- return exc_info.value
-
- async def wait_for_response() -> Error:
- with pytest.raises(Error) as exc_info:
- async with page.expect_response(server.EMPTY_PAGE):
- pass
- return exc_info.value
-
- results = await asyncio.gather(wait_for_request(), wait_for_response(), page.close())
- for i in range(2):
- error = results[i]
- assert error
- assert TARGET_CLOSED_ERROR_MESSAGE in error.message
- assert "Timeout" not in error.message
-
-
-async def test_close_should_be_callable_twice(context: BrowserContext) -> None:
- page = await context.new_page()
- await asyncio.gather(
- page.close(),
- page.close(),
- )
- await page.close()
-
-
-async def test_load_should_fire_when_expected(page: Page) -> None:
- async with page.expect_event("load"):
- await page.goto("about:blank")
-
-
-@pytest.mark.skip("FIXME")
-async def test_should_work_with_wait_for_loadstate(page: Page, server: Server) -> None:
- messages = []
-
- def _handler(request: TestServerRequest) -> None:
- messages.append("route")
- request.setHeader("Content-Type", "text/html")
- request.write(b" ")
- request.finish()
-
- server.set_route(
- "/empty.html",
- _handler,
- )
-
- await page.set_content(f'empty.html ')
-
- async def wait_for_clickload() -> None:
- await page.click("a")
- await page.wait_for_load_state("load")
- messages.append("clickload")
-
- async def wait_for_page_load() -> None:
- await page.wait_for_event("load")
- messages.append("load")
-
- await asyncio.gather(
- wait_for_clickload(),
- wait_for_page_load(),
- )
-
- assert messages == ["route", "load", "clickload"]
-
-
-async def test_async_stacks_should_work(page: Page, server: Server) -> None:
- await page.route("**/empty.html", lambda route, response: asyncio.create_task(route.abort()))
- with pytest.raises(Error) as exc_info:
- await page.goto(server.EMPTY_PAGE)
- assert exc_info.value.stack
- assert __file__ in exc_info.value.stack
-
-
-async def test_opener_should_provide_access_to_the_opener_page(page: Page) -> None:
- async with page.expect_popup() as popup_info:
- await page.evaluate("window.open('about:blank')")
- popup = await popup_info.value
- opener = await popup.opener()
- assert opener == page
-
-
-async def test_opener_should_return_null_if_parent_page_has_been_closed(
- page: Page,
-) -> None:
- async with page.expect_popup() as popup_info:
- await page.evaluate("window.open('about:blank')")
- popup = await popup_info.value
- await page.close()
- opener = await popup.opener()
- assert opener is None
-
-
-async def test_domcontentloaded_should_fire_when_expected(page: Page, server: Server) -> None:
- future = asyncio.create_task(page.goto("about:blank"))
- async with page.expect_event("domcontentloaded"):
- pass
- await future
-
-
-async def test_wait_for_request(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- async with page.expect_request(server.PREFIX + "/digits/2.png") as request_info:
- await page.evaluate(
- """() => {
- fetch('/digits/1.png')
- fetch('/digits/2.png')
- fetch('/digits/3.png')
- }"""
- )
- request = await request_info.value
- assert request.url == server.PREFIX + "/digits/2.png"
-
-
-async def test_wait_for_request_should_work_with_predicate(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- async with page.expect_request(
- lambda request: request.url == server.PREFIX + "/digits/2.png"
- ) as request_info:
- await page.evaluate(
- """() => {
- fetch('/digits/1.png')
- fetch('/digits/2.png')
- fetch('/digits/3.png')
- }"""
- )
- request = await request_info.value
- assert request.url == server.PREFIX + "/digits/2.png"
-
-
-async def test_wait_for_request_should_timeout(page: Page, server: Server) -> None:
- with pytest.raises(Error) as exc_info:
- async with page.expect_event("request", timeout=1):
- pass
- assert exc_info.type is TimeoutError
-
-
-async def test_wait_for_request_should_respect_default_timeout(page: Page, server: Server) -> None:
- page.set_default_timeout(1)
- with pytest.raises(Error) as exc_info:
- async with page.expect_event("request", lambda _: False):
- pass
- assert exc_info.type is TimeoutError
-
-
-async def test_wait_for_request_should_work_with_no_timeout(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- async with page.expect_request(server.PREFIX + "/digits/2.png", timeout=0) as request_info:
- await page.evaluate(
- """() => setTimeout(() => {
- fetch('/digits/1.png')
- fetch('/digits/2.png')
- fetch('/digits/3.png')
- }, 50)"""
- )
- request = await request_info.value
- assert request.url == server.PREFIX + "/digits/2.png"
-
-
-async def test_wait_for_request_should_work_with_url_match(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- async with page.expect_request(re.compile(r"digits\/\d\.png")) as request_info:
- await page.evaluate("fetch('/digits/1.png')")
- request = await request_info.value
- assert request.url == server.PREFIX + "/digits/1.png"
-
-
-async def test_wait_for_event_should_fail_with_error_upon_disconnect(
- page: Page,
-) -> None:
- with pytest.raises(Error) as exc_info:
- async with page.expect_download():
- await page.close()
- assert TARGET_CLOSED_ERROR_MESSAGE in exc_info.value.message
-
-
-async def test_wait_for_response_should_work(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- async with page.expect_response(server.PREFIX + "/digits/2.png") as response_info:
- await page.evaluate(
- """() => {
- fetch('/digits/1.png')
- fetch('/digits/2.png')
- fetch('/digits/3.png')
- }"""
- )
- response = await response_info.value
- assert response.url == server.PREFIX + "/digits/2.png"
-
-
-async def test_wait_for_response_should_respect_timeout(page: Page) -> None:
- with pytest.raises(Error) as exc_info:
- async with page.expect_response("**/*", timeout=1):
- pass
- assert exc_info.type is TimeoutError
-
-
-async def test_wait_for_response_should_respect_default_timeout(page: Page) -> None:
- page.set_default_timeout(1)
- with pytest.raises(Error) as exc_info:
- async with page.expect_response(lambda _: False):
- pass
- assert exc_info.type is TimeoutError
-
-
-async def test_wait_for_response_should_work_with_predicate(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- async with page.expect_response(
- lambda response: response.url == server.PREFIX + "/digits/2.png"
- ) as response_info:
- await page.evaluate(
- """() => {
- fetch('/digits/1.png')
- fetch('/digits/2.png')
- fetch('/digits/3.png')
- }"""
- )
- response = await response_info.value
- assert response.url == server.PREFIX + "/digits/2.png"
-
-
-async def test_wait_for_response_should_work_with_no_timeout(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- async with page.expect_response(server.PREFIX + "/digits/2.png") as response_info:
- await page.evaluate(
- """() => {
- fetch('/digits/1.png')
- fetch('/digits/2.png')
- fetch('/digits/3.png')
- }"""
- )
- response = await response_info.value
- assert response.url == server.PREFIX + "/digits/2.png"
-
-
-async def test_wait_for_response_should_use_context_timeout(
- page: Page, context: BrowserContext, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
-
- context.set_default_timeout(1_000)
- with pytest.raises(Error) as exc_info:
- async with page.expect_response("https://playwright.dev"):
- pass
- assert exc_info.type is TimeoutError
- assert "Timeout 1000ms exceeded" in exc_info.value.message
-
-
-async def test_expect_response_should_not_hang_when_predicate_throws(
- page: Page,
-) -> None:
- with pytest.raises(Exception, match="Oops!"):
- async with page.expect_response("**/*"):
- raise Exception("Oops!")
-
-
-async def test_expose_binding(page: Page) -> None:
- binding_source = []
-
- def binding(source: Dict, a: int, b: int) -> int:
- binding_source.append(source)
- return a + b
-
- await page.expose_binding("add", lambda source, a, b: binding(source, a, b))
-
- result = await page.evaluate("add(5, 6)")
-
- assert binding_source[0]["context"] == page.context
- assert binding_source[0]["page"] == page
- assert binding_source[0]["frame"] == page.main_frame
- assert result == 11
-
-
-async def test_expose_function(page: Page, server: Server) -> None:
- await page.expose_function("compute", lambda a, b: a * b)
- result = await page.evaluate("compute(9, 4)")
- assert result == 36
-
-
-async def test_expose_function_should_throw_exception_in_page_context(
- page: Page, server: Server
-) -> None:
- def throw() -> None:
- raise Exception("WOOF WOOF")
-
- await page.expose_function("woof", lambda: throw())
- result = await page.evaluate(
- """async() => {
- try {
- await woof()
- } catch (e) {
- return {message: e.message, stack: e.stack}
- }
- }"""
- )
- assert result["message"] == "WOOF WOOF"
- assert __file__ in result["stack"]
-
-
-async def test_expose_function_should_be_callable_from_inside_add_init_script(
- page: Page,
-) -> None:
- called = []
- await page.expose_function("woof", lambda: called.append(True))
- await page.add_init_script("woof()")
- await page.reload()
- assert called == [True]
-
-
-async def test_expose_function_should_survive_navigation(page: Page, server: Server) -> None:
- await page.expose_function("compute", lambda a, b: a * b)
- await page.goto(server.EMPTY_PAGE)
- result = await page.evaluate("compute(9, 4)")
- assert result == 36
-
-
-async def test_expose_function_should_await_returned_promise(page: Page) -> None:
- async def mul(a: int, b: int) -> int:
- return a * b
-
- await page.expose_function("compute", mul)
- assert await page.evaluate("compute(3, 5)") == 15
-
-
-async def test_expose_function_should_work_on_frames(page: Page, server: Server) -> None:
- await page.expose_function("compute", lambda a, b: a * b)
- await page.goto(server.PREFIX + "/frames/nested-frames.html")
- frame = page.frames[1]
- assert await frame.evaluate("compute(3, 5)") == 15
-
-
-async def test_expose_function_should_work_on_frames_before_navigation(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/frames/nested-frames.html")
- await page.expose_function("compute", lambda a, b: a * b)
- frame = page.frames[1]
- assert await frame.evaluate("compute(3, 5)") == 15
-
-
-async def test_expose_function_should_work_after_cross_origin_navigation(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- await page.expose_function("compute", lambda a, b: a * b)
- await page.goto(server.CROSS_PROCESS_PREFIX + "/empty.html")
- assert await page.evaluate("compute(9, 4)") == 36
-
-
-async def test_expose_function_should_work_with_complex_objects(page: Page, server: Server) -> None:
- await page.expose_function("complexObject", lambda a, b: dict(x=a["x"] + b["x"]))
- result = await page.evaluate("complexObject({x: 5}, {x: 2})")
- assert result["x"] == 7
-
-
-async def test_expose_bindinghandle_should_work(page: Page, server: Server) -> None:
- targets: List[JSHandle] = []
-
- def logme(t: JSHandle) -> int:
- targets.append(t)
- return 17
-
- await page.expose_binding("logme", lambda source, t: logme(t), handle=True)
- result = await page.evaluate("logme({ foo: 42 })")
- assert (await targets[0].evaluate("x => x.foo")) == 42
- assert result == 17
-
-
-async def test_page_error_should_fire(page: Page, server: Server, browser_name: str) -> None:
- url = server.PREFIX + "/error.html"
- async with page.expect_event("pageerror") as error_info:
- await page.goto(url)
- error = await error_info.value
- assert error.name == "Error"
- assert error.message == "Fancy error!"
- # Note that WebKit reports the stack of the 'throw' statement instead of the Error constructor call.
- if browser_name == "chromium":
- assert (
- error.stack
- == """Error: Fancy error!
- at c (myscript.js:14:11)
- at b (myscript.js:10:5)
- at a (myscript.js:6:5)
- at myscript.js:3:1"""
- )
- if browser_name == "firefox":
- assert (
- error.stack
- == """Error: Fancy error!
- at c (myscript.js:14:11)
- at b (myscript.js:10:5)
- at a (myscript.js:6:5)
- at (myscript.js:3:1)"""
- )
- if browser_name == "webkit":
- assert (
- error.stack
- == f"""Error: Fancy error!
- at c ({url}:14:36)
- at b ({url}:10:6)
- at a ({url}:6:6)
- at global code ({url}:3:2)"""
- )
-
-
-async def test_page_error_should_handle_odd_values(page: Page) -> None:
- cases = [["null", "null"], ["undefined", "undefined"], ["0", "0"], ['""', ""]]
- for [value, message] in cases:
- async with page.expect_event("pageerror") as error_info:
- await page.evaluate(f"() => setTimeout(() => {{ throw {value}; }}, 0)")
- error = await error_info.value
- assert error.message == message
-
-
-async def test_page_error_should_handle_object(page: Page, is_chromium: bool) -> None:
- async with page.expect_event("pageerror") as error_info:
- await page.evaluate("() => setTimeout(() => { throw {}; }, 0)")
- error = await error_info.value
- assert error.message == "Object" if is_chromium else "[object Object]"
-
-
-async def test_page_error_should_handle_window(page: Page, is_chromium: bool) -> None:
- async with page.expect_event("pageerror") as error_info:
- await page.evaluate("() => setTimeout(() => { throw window; }, 0)")
- error = await error_info.value
- assert error.message == "Window" if is_chromium else "[object Window]"
-
-
-async def test_page_error_should_pass_error_name_property(page: Page) -> None:
- async with page.expect_event("pageerror") as error_info:
- await page.evaluate(
- """() => setTimeout(() => {
- const error = new Error("my-message");
- error.name = "my-name";
- throw error;
- }, 0)
- """
- )
- error = await error_info.value
- assert error.message == "my-message"
- assert error.name == "my-name"
-
-
-expected_output = "hello
"
-
-
-async def test_set_content_should_work(page: Page, server: Server) -> None:
- await page.set_content("hello
")
- result = await page.content()
- assert result == expected_output
-
-
-async def test_set_content_should_work_with_domcontentloaded(page: Page, server: Server) -> None:
- await page.set_content("hello
", wait_until="domcontentloaded")
- result = await page.content()
- assert result == expected_output
-
-
-async def test_set_content_should_work_with_doctype(page: Page, server: Server) -> None:
- doctype = ""
- await page.set_content(f"{doctype}hello
")
- result = await page.content()
- assert result == f"{doctype}{expected_output}"
-
-
-async def test_set_content_should_work_with_HTML_4_doctype(page: Page, server: Server) -> None:
- doctype = (
- ''
- )
- await page.set_content(f"{doctype}hello
")
- result = await page.content()
- assert result == f"{doctype}{expected_output}"
-
-
-async def test_set_content_should_respect_timeout(page: Page, server: Server) -> None:
- img_path = "/img.png"
- # stall for image
- server.set_route(img_path, lambda request: None)
- with pytest.raises(Error) as exc_info:
- await page.set_content(f' ', timeout=1)
- assert exc_info.type is TimeoutError
-
-
-async def test_set_content_should_respect_default_navigation_timeout(
- page: Page, server: Server
-) -> None:
- page.set_default_navigation_timeout(1)
- img_path = "/img.png"
- # stall for image
- await page.route(img_path, lambda route, request: None)
-
- with pytest.raises(Error) as exc_info:
- await page.set_content(f' ')
- assert "Timeout 1ms exceeded" in exc_info.value.message
- assert exc_info.type is TimeoutError
-
-
-async def test_set_content_should_await_resources_to_load(page: Page, server: Server) -> None:
- img_route: "asyncio.Future[Route]" = asyncio.Future()
- await page.route("**/img.png", lambda route, request: img_route.set_result(route))
- loaded = []
-
- async def load() -> None:
- await page.set_content(f' ')
- loaded.append(True)
-
- content_promise = asyncio.create_task(load())
- await asyncio.sleep(0) # execute scheduled tasks, but don't await them
- route = await img_route
- assert loaded == []
- asyncio.create_task(route.continue_())
- await content_promise
-
-
-async def test_set_content_should_work_with_tricky_content(page: Page) -> None:
- await page.set_content("hello world
" + "\x7F")
- assert await page.eval_on_selector("div", "div => div.textContent") == "hello world"
-
-
-async def test_set_content_should_work_with_accents(page: Page) -> None:
- await page.set_content("aberración
")
- assert await page.eval_on_selector("div", "div => div.textContent") == "aberración"
-
-
-async def test_set_content_should_work_with_emojis(page: Page) -> None:
- await page.set_content("🐥
")
- assert await page.eval_on_selector("div", "div => div.textContent") == "🐥"
-
-
-async def test_set_content_should_work_with_newline(page: Page) -> None:
- await page.set_content("\n
")
- assert await page.eval_on_selector("div", "div => div.textContent") == "\n"
-
-
-async def test_add_script_tag_should_work_with_a_url(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- script_handle = await page.add_script_tag(url="/injectedfile.js")
- assert script_handle.as_element()
- assert await page.evaluate("__injected") == 42
-
-
-async def test_add_script_tag_should_work_with_a_url_and_type_module(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- await page.add_script_tag(url="/es6/es6import.js", type="module")
- assert await page.evaluate("__es6injected") == 42
-
-
-async def test_add_script_tag_should_work_with_a_path_and_type_module(
- page: Page, server: Server, assetdir: Path
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- await page.add_script_tag(path=assetdir / "es6" / "es6pathimport.js", type="module")
- await page.wait_for_function("window.__es6injected")
- assert await page.evaluate("__es6injected") == 42
-
-
-async def test_add_script_tag_should_work_with_a_content_and_type_module(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- await page.add_script_tag(
- content="import num from '/es6/es6module.js';window.__es6injected = num;",
- type="module",
- )
- await page.wait_for_function("window.__es6injected")
- assert await page.evaluate("__es6injected") == 42
-
-
-async def test_add_script_tag_should_throw_an_error_if_loading_from_url_fail(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- with pytest.raises(Error) as exc_info:
- await page.add_script_tag(url="/nonexistfile.js")
- assert exc_info.value
-
-
-async def test_add_script_tag_should_work_with_a_path(
- page: Page, server: Server, assetdir: Path
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- script_handle = await page.add_script_tag(path=assetdir / "injectedfile.js")
- assert script_handle.as_element()
- assert await page.evaluate("__injected") == 42
-
-
-@pytest.mark.skip_browser("webkit")
-async def test_add_script_tag_should_include_source_url_when_path_is_provided(
- page: Page, server: Server, assetdir: Path
-) -> None:
- # Lacking sourceURL support in WebKit
- await page.goto(server.EMPTY_PAGE)
- await page.add_script_tag(path=assetdir / "injectedfile.js")
- result = await page.evaluate("__injectedError.stack")
- assert os.path.join("assets", "injectedfile.js") in result
-
-
-async def test_add_script_tag_should_work_with_content(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- script_handle = await page.add_script_tag(content="window.__injected = 35;")
- assert script_handle.as_element()
- assert await page.evaluate("__injected") == 35
-
-
-@pytest.mark.skip_browser("firefox")
-async def test_add_script_tag_should_throw_when_added_with_content_to_the_csp_page(
- page: Page, server: Server
-) -> None:
- # Firefox fires onload for blocked script before it issues the CSP console error.
- await page.goto(server.PREFIX + "/csp.html")
- with pytest.raises(Error) as exc_info:
- await page.add_script_tag(content="window.__injected = 35;")
- assert exc_info.value
-
-
-async def test_add_script_tag_should_throw_when_added_with_URL_to_the_csp_page(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/csp.html")
- with pytest.raises(Error) as exc_info:
- await page.add_script_tag(url=server.CROSS_PROCESS_PREFIX + "/injectedfile.js")
- assert exc_info.value
-
-
-async def test_add_script_tag_should_throw_a_nice_error_when_the_request_fails(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- url = server.PREFIX + "/this_does_not_exist.js"
- with pytest.raises(Error) as exc_info:
- await page.add_script_tag(url=url)
- assert url in exc_info.value.message
-
-
-async def test_add_style_tag_should_work_with_a_url(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- style_handle = await page.add_style_tag(url="/injectedstyle.css")
- assert style_handle.as_element()
- assert (
- await page.evaluate(
- "window.getComputedStyle(document.querySelector('body')).getPropertyValue('background-color')"
- )
- == "rgb(255, 0, 0)"
- )
-
-
-async def test_add_style_tag_should_throw_an_error_if_loading_from_url_fail(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- with pytest.raises(Error) as exc_info:
- await page.add_style_tag(url="/nonexistfile.js")
- assert exc_info.value
-
-
-async def test_add_style_tag_should_work_with_a_path(
- page: Page, server: Server, assetdir: Path
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- style_handle = await page.add_style_tag(path=assetdir / "injectedstyle.css")
- assert style_handle.as_element()
- assert (
- await page.evaluate(
- "window.getComputedStyle(document.querySelector('body')).getPropertyValue('background-color')"
- )
- == "rgb(255, 0, 0)"
- )
-
-
-async def test_add_style_tag_should_include_source_url_when_path_is_provided(
- page: Page, server: Server, assetdir: Path
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- await page.add_style_tag(path=assetdir / "injectedstyle.css")
- style_handle = await page.query_selector("style")
- style_content = await page.evaluate("style => style.innerHTML", style_handle)
- assert os.path.join("assets", "injectedstyle.css") in style_content
-
-
-async def test_add_style_tag_should_work_with_content(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- style_handle = await page.add_style_tag(content="body { background-color: green; }")
- assert style_handle.as_element()
- assert (
- await page.evaluate(
- "window.getComputedStyle(document.querySelector('body')).getPropertyValue('background-color')"
- )
- == "rgb(0, 128, 0)"
- )
-
-
-async def test_add_style_tag_should_throw_when_added_with_content_to_the_CSP_page(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/csp.html")
- with pytest.raises(Error) as exc_info:
- await page.add_style_tag(content="body { background-color: green; }")
- assert exc_info.value
-
-
-async def test_add_style_tag_should_throw_when_added_with_URL_to_the_CSP_page(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/csp.html")
- with pytest.raises(Error) as exc_info:
- await page.add_style_tag(url=server.CROSS_PROCESS_PREFIX + "/injectedstyle.css")
- assert exc_info.value
-
-
-async def test_url_should_work(page: Page, server: Server) -> None:
- assert page.url == "about:blank"
- await page.goto(server.EMPTY_PAGE)
- assert page.url == server.EMPTY_PAGE
-
-
-async def test_url_should_include_hashes(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE + "#hash")
- assert page.url == server.EMPTY_PAGE + "#hash"
- await page.evaluate("window.location.hash = 'dynamic'")
- assert page.url == server.EMPTY_PAGE + "#dynamic"
-
-
-async def test_title_should_return_the_page_title(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/title.html")
- assert await page.title() == "Woof-Woof"
-
-
-async def give_it_a_chance_to_fill(page: Page) -> None:
- for i in range(5):
- await page.evaluate(
- "() => new Promise(f => requestAnimationFrame(() => requestAnimationFrame(f)))"
- )
-
-
-async def test_fill_should_fill_textarea(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/textarea.html")
- await page.fill("textarea", "some value")
- assert await page.evaluate("result") == "some value"
-
-
-async def test_fill_should_fill_input(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/textarea.html")
- await page.fill("input", "some value")
- assert await page.evaluate("result") == "some value"
-
-
-async def test_fill_should_throw_on_unsupported_inputs(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/textarea.html")
- for type in [
- "button",
- "checkbox",
- "file",
- "image",
- "radio",
- "reset",
- "submit",
- ]:
- await page.eval_on_selector(
- "input", "(input, type) => input.setAttribute('type', type)", type
- )
- with pytest.raises(Error) as exc_info:
- await page.fill("input", "")
- assert f'Input of type "{type}" cannot be filled' in exc_info.value.message
-
-
-async def test_fill_should_fill_different_input_types(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/textarea.html")
- for type in ["password", "search", "tel", "text", "url"]:
- await page.eval_on_selector(
- "input", "(input, type) => input.setAttribute('type', type)", type
- )
- await page.fill("input", "text " + type)
- assert await page.evaluate("result") == "text " + type
-
-
-async def test_fill_should_fill_date_input_after_clicking(page: Page, server: Server) -> None:
- await page.set_content(" ")
- await page.click("input")
- await page.fill("input", "2020-03-02")
- assert await page.eval_on_selector("input", "input => input.value") == "2020-03-02"
-
-
-@pytest.mark.skip_browser("webkit")
-async def test_fill_should_throw_on_incorrect_date(page: Page, server: Server) -> None:
- # Disabled as in upstream, we should validate time in the Playwright lib
- await page.set_content(" ")
- with pytest.raises(Error) as exc_info:
- await page.fill("input", "2020-13-05")
- assert "Malformed value" in exc_info.value.message
-
-
-async def test_fill_should_fill_time_input(page: Page, server: Server) -> None:
- await page.set_content(" ")
- await page.fill("input", "13:15")
- assert await page.eval_on_selector("input", "input => input.value") == "13:15"
-
-
-@pytest.mark.skip_browser("webkit")
-async def test_fill_should_throw_on_incorrect_time(page: Page, server: Server) -> None:
- # Disabled as in upstream, we should validate time in the Playwright lib
- await page.set_content(" ")
- with pytest.raises(Error) as exc_info:
- await page.fill("input", "25:05")
- assert "Malformed value" in exc_info.value.message
-
-
-async def test_fill_should_fill_datetime_local_input(page: Page, server: Server) -> None:
- await page.set_content(" ")
- await page.fill("input", "2020-03-02T05:15")
- assert await page.eval_on_selector("input", "input => input.value") == "2020-03-02T05:15"
-
-
-@pytest.mark.only_browser("chromium")
-async def test_fill_should_throw_on_incorrect_datetime_local(page: Page) -> None:
- await page.set_content(" ")
- with pytest.raises(Error) as exc_info:
- await page.fill("input", "abc")
- assert "Malformed value" in exc_info.value.message
-
-
-async def test_fill_should_fill_contenteditable(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/textarea.html")
- await page.fill("div[contenteditable]", "some value")
- assert (
- await page.eval_on_selector("div[contenteditable]", "div => div.textContent")
- == "some value"
- )
-
-
-async def test_fill_should_fill_elements_with_existing_value_and_selection(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/input/textarea.html")
-
- await page.eval_on_selector("input", "input => input.value = 'value one'")
- await page.fill("input", "another value")
- assert await page.evaluate("result") == "another value"
-
- await page.eval_on_selector(
- "input",
- """input => {
- input.selectionStart = 1
- input.selectionEnd = 2
- }""",
- )
-
- await page.fill("input", "maybe this one")
- assert await page.evaluate("result") == "maybe this one"
-
- await page.eval_on_selector(
- "div[contenteditable]",
- """div => {
- div.innerHTML = 'some text some more text and even more text'
- range = document.createRange()
- range.selectNodeContents(div.querySelector('span'))
- selection = window.getSelection()
- selection.removeAllRanges()
- selection.addRange(range)
- }""",
- )
-
- await page.fill("div[contenteditable]", "replace with this")
- assert (
- await page.eval_on_selector("div[contenteditable]", "div => div.textContent")
- == "replace with this"
- )
-
-
-async def test_fill_should_throw_when_element_is_not_an_input_textarea_or_contenteditable(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/input/textarea.html")
- with pytest.raises(Error) as exc_info:
- await page.fill("body", "")
- assert "Element is not an " in exc_info.value.message
-
-
-async def test_fill_should_throw_if_passed_a_non_string_value(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/textarea.html")
- with pytest.raises(Error) as exc_info:
- await page.fill("textarea", 123) # type: ignore
- assert "expected string, got number" in exc_info.value.message
-
-
-async def test_fill_should_retry_on_disabled_element(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/textarea.html")
- await page.eval_on_selector("input", "i => i.disabled = true")
- done = []
-
- async def fill() -> None:
- await page.fill("input", "some value")
- done.append(True)
-
- promise = asyncio.create_task(fill())
- await give_it_a_chance_to_fill(page)
- assert done == []
- assert await page.evaluate("result") == ""
-
- await page.eval_on_selector("input", "i => i.disabled = false")
- await promise
- assert await page.evaluate("result") == "some value"
-
-
-async def test_fill_should_retry_on_readonly_element(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/textarea.html")
- await page.eval_on_selector("textarea", "i => i.readOnly = true")
- done = []
-
- async def fill() -> None:
- await page.fill("textarea", "some value")
- done.append(True)
-
- promise = asyncio.create_task(fill())
- await give_it_a_chance_to_fill(page)
- assert done == []
- assert await page.evaluate("result") == ""
-
- await page.eval_on_selector("textarea", "i => i.readOnly = false")
- await promise
- assert await page.evaluate("result") == "some value"
-
-
-async def test_fill_should_retry_on_invisible_element(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/textarea.html")
- await page.eval_on_selector("input", "i => i.style.display = 'none'")
- done = []
-
- async def fill() -> None:
- await page.fill("input", "some value")
- done.append(True)
-
- promise = asyncio.create_task(fill())
- await give_it_a_chance_to_fill(page)
- assert done == []
- assert await page.evaluate("result") == ""
-
- await page.eval_on_selector("input", "i => i.style.display = 'inline'")
- await promise
- assert await page.evaluate("result") == "some value"
-
-
-async def test_fill_should_be_able_to_fill_the_body(page: Page) -> None:
- await page.set_content('')
- await page.fill("body", "some value")
- assert await page.evaluate("document.body.textContent") == "some value"
-
-
-async def test_fill_should_fill_fixed_position_input(page: Page) -> None:
- await page.set_content(' ')
- await page.fill("input", "some value")
- assert await page.evaluate("document.querySelector('input').value") == "some value"
-
-
-async def test_fill_should_be_able_to_fill_when_focus_is_in_the_wrong_frame(
- page: Page,
-) -> None:
- await page.set_content(
- """
-
-
- """
- )
- await page.focus("iframe")
- await page.fill("div", "some value")
- assert await page.eval_on_selector("div", "d => d.textContent") == "some value"
-
-
-async def test_fill_should_be_able_to_fill_the_input_type_number_(page: Page) -> None:
- await page.set_content(' ')
- await page.fill("input", "42")
- assert await page.evaluate("input.value") == "42"
-
-
-async def test_fill_should_be_able_to_fill_exponent_into_the_input_type_number_(
- page: Page,
-) -> None:
- await page.set_content(' ')
- await page.fill("input", "-10e5")
- assert await page.evaluate("input.value") == "-10e5"
-
-
-async def test_fill_should_be_able_to_fill_input_type_number__with_empty_string(
- page: Page,
-) -> None:
- await page.set_content(' ')
- await page.fill("input", "")
- assert await page.evaluate("input.value") == ""
-
-
-async def test_fill_should_not_be_able_to_fill_text_into_the_input_type_number_(
- page: Page,
-) -> None:
- await page.set_content(' ')
- with pytest.raises(Error) as exc_info:
- await page.fill("input", "abc")
- assert "Cannot type text into input[type=number]" in exc_info.value.message
-
-
-async def test_fill_should_be_able_to_clear_using_fill(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/textarea.html")
- await page.fill("input", "some value")
- assert await page.evaluate("result") == "some value"
- await page.fill("input", "")
- assert await page.evaluate("result") == ""
-
-
-async def test_close_event_should_work_with_window_close(page: Page, server: Server) -> None:
- async with page.expect_popup() as popup_info:
- await page.evaluate("window['newPage'] = window.open('about:blank')")
- popup = await popup_info.value
-
- async with popup.expect_event("close"):
- await page.evaluate("window['newPage'].close()")
-
-
-async def test_close_event_should_work_with_page_close(
- context: BrowserContext, server: Server
-) -> None:
- page = await context.new_page()
- async with page.expect_event("close"):
- await page.close()
-
-
-async def test_page_context_should_return_the_correct_browser_instance(
- page: Page, context: BrowserContext
-) -> None:
- assert page.context == context
-
-
-async def test_frame_should_respect_name(page: Page, server: Server) -> None:
- await page.set_content("")
- assert page.frame(name="bogus") is None
- frame = page.frame(name="target")
- assert frame
- assert frame == page.main_frame.child_frames[0]
-
-
-async def test_frame_should_respect_url(page: Page, server: Server) -> None:
- await page.set_content(f'')
- assert page.frame(url=re.compile(r"bogus")) is None
- assert must(page.frame(url=re.compile(r"empty"))).url == server.EMPTY_PAGE
-
-
-async def test_press_should_work(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/textarea.html")
- await page.press("textarea", "a")
- assert await page.evaluate("document.querySelector('textarea').value") == "a"
-
-
-async def test_frame_press_should_work(page: Page, server: Server) -> None:
- await page.set_content(
- f''
- )
- frame = page.frame("inner")
- assert frame
- await frame.press("textarea", "a")
- assert await frame.evaluate("document.querySelector('textarea').value") == "a"
-
-
-async def test_should_emulate_reduced_motion(page: Page, server: Server) -> None:
- assert await page.evaluate("matchMedia('(prefers-reduced-motion: no-preference)').matches")
- await page.emulate_media(reduced_motion="reduce")
- assert await page.evaluate("matchMedia('(prefers-reduced-motion: reduce)').matches")
- assert not await page.evaluate("matchMedia('(prefers-reduced-motion: no-preference)').matches")
- await page.emulate_media(reduced_motion="no-preference")
- assert not await page.evaluate("matchMedia('(prefers-reduced-motion: reduce)').matches")
- assert await page.evaluate("matchMedia('(prefers-reduced-motion: no-preference)').matches")
-
-
-async def test_input_value(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/textarea.html")
-
- await page.fill("input", "my-text-content")
- assert await page.input_value("input") == "my-text-content"
-
- await page.fill("input", "")
- assert await page.input_value("input") == ""
-
-
-async def test_drag_and_drop_helper_method(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/drag-n-drop.html")
- await page.drag_and_drop("#source", "#target")
- assert (
- await page.eval_on_selector(
- "#target", "target => target.contains(document.querySelector('#source'))"
- )
- is True
- )
-
-
-async def test_drag_and_drop_with_position(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- await page.set_content(
- """
-
-
-
-
- """
- )
- events_handle = await page.evaluate_handle(
- """
- () => {
- const events = [];
- document.getElementById('red').addEventListener('mousedown', event => {
- events.push({
- type: 'mousedown',
- x: event.offsetX,
- y: event.offsetY,
- });
- });
- document.getElementById('blue').addEventListener('mouseup', event => {
- events.push({
- type: 'mouseup',
- x: event.offsetX,
- y: event.offsetY,
- });
- });
- return events;
- }
- """
- )
- await page.drag_and_drop(
- "#red",
- "#blue",
- source_position={"x": 34, "y": 7},
- target_position={"x": 10, "y": 20},
- )
- assert await events_handle.json_value() == [
- {"type": "mousedown", "x": 34, "y": 7},
- {"type": "mouseup", "x": 10, "y": 20},
- ]
-
-
-async def test_should_check_box_using_set_checked(page: Page) -> None:
- await page.set_content("` `")
- await page.set_checked("input", True)
- assert await page.evaluate("checkbox.checked") is True
- await page.set_checked("input", False)
- assert await page.evaluate("checkbox.checked") is False
-
-
-async def test_should_set_bodysize_and_headersize(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- async with page.expect_request("*/**") as request_info:
- await page.evaluate(
- "() => fetch('./get', { method: 'POST', body: '12345'}).then(r => r.text())"
- )
- request = await request_info.value
- sizes = await request.sizes()
- assert sizes["requestBodySize"] == 5
- assert sizes["requestHeadersSize"] >= 300
-
-
-async def test_should_set_bodysize_to_0(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- async with page.expect_request("*/**") as request_info:
- await page.evaluate("() => fetch('./get').then(r => r.text())")
- request = await request_info.value
- sizes = await request.sizes()
- assert sizes["requestBodySize"] == 0
- assert sizes["requestHeadersSize"] >= 200
-
-
-@pytest.mark.skip_browser("webkit") # https://bugs.webkit.org/show_bug.cgi?id=225281
-async def test_should_emulate_forced_colors(page: Page) -> None:
- assert await page.evaluate("matchMedia('(forced-colors: none)').matches")
- await page.emulate_media(forced_colors="none")
- assert await page.evaluate("matchMedia('(forced-colors: none)').matches")
- assert not await page.evaluate("matchMedia('(forced-colors: active)').matches")
- await page.emulate_media(forced_colors="active")
- assert await page.evaluate("matchMedia('(forced-colors: active)').matches")
- assert not await page.evaluate("matchMedia('(forced-colors: none)').matches")
-
-
-async def test_should_not_throw_when_continuing_while_page_is_closing(
- page: Page, server: Server
-) -> None:
- done: Optional[asyncio.Future] = None
-
- def handle_route(route: Route) -> None:
- nonlocal done
- done = asyncio.gather(route.continue_(), page.close())
-
- await page.route("**/*", handle_route)
- with pytest.raises(Error):
- await page.goto(server.EMPTY_PAGE)
- await must(done)
-
-
-async def test_should_not_throw_when_continuing_after_page_is_closed(
- page: Page, server: Server
-) -> None:
- done: "asyncio.Future[bool]" = asyncio.Future()
-
- async def handle_route(route: Route) -> None:
- await page.close()
- await route.continue_()
- nonlocal done
- done.set_result(True)
-
- await page.route("**/*", handle_route)
- with pytest.raises(Error):
- await page.goto(server.EMPTY_PAGE)
- await done
-
-
-async def test_expose_binding_should_serialize_cycles(page: Page) -> None:
- binding_values = []
-
- def binding(source: Dict, o: Dict) -> None:
- binding_values.append(o)
-
- await page.expose_binding("log", lambda source, o: binding(source, o))
- await page.evaluate("const a = {}; a.b = a; window.log(a)")
- assert binding_values[0]["b"] == binding_values[0]
-
-
-async def test_page_pause_should_reset_default_timeouts(
- page: Page, headless: bool, server: Server
-) -> None:
- if not headless:
- pytest.skip()
-
- await page.goto(server.EMPTY_PAGE)
- await page.pause()
- with pytest.raises(Error, match="Timeout 30000ms exceeded."):
- await page.get_by_text("foo").click()
-
-
-async def test_page_pause_should_reset_custom_timeouts(
- page: Page, headless: bool, server: Server
-) -> None:
- if not headless:
- pytest.skip()
-
- page.set_default_timeout(123)
- page.set_default_navigation_timeout(456)
- await page.goto(server.EMPTY_PAGE)
- await page.pause()
- with pytest.raises(Error, match="Timeout 123ms exceeded."):
- await page.get_by_text("foo").click()
-
- server.set_route("/empty.html", lambda route: None)
- with pytest.raises(Error, match="Timeout 456ms exceeded."):
- await page.goto(server.EMPTY_PAGE)
diff --git a/tests/async/test_page_add_locator_handler.py b/tests/async/test_page_add_locator_handler.py
deleted file mode 100644
index 412474f..0000000
--- a/tests/async/test_page_add_locator_handler.py
+++ /dev/null
@@ -1,377 +0,0 @@
-# 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 Error, Locator, Page, expect
-from tests.server import Server
-from tests.utils import TARGET_CLOSED_ERROR_MESSAGE
-
-
-async def test_should_work(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/handle-locator.html")
-
- before_count = 0
- after_count = 0
-
- original_locator = page.get_by_text("This interstitial covers the button")
-
- async def handler(locator: Locator) -> None:
- nonlocal original_locator
- assert locator == original_locator
- nonlocal before_count
- nonlocal after_count
- before_count += 1
- await page.locator("#close").click()
- after_count += 1
-
- await page.add_locator_handler(original_locator, handler)
-
- for args in [
- ["mouseover", 1],
- ["mouseover", 1, "capture"],
- ["mouseover", 2],
- ["mouseover", 2, "capture"],
- ["pointerover", 1],
- ["pointerover", 1, "capture"],
- ["none", 1],
- ["remove", 1],
- ["hide", 1],
- ]:
- await page.locator("#aside").hover()
- before_count = 0
- after_count = 0
- await page.evaluate(
- "(args) => { window.clicked = 0; window.setupAnnoyingInterstitial(...args); }",
- args,
- )
- assert before_count == 0
- assert after_count == 0
- await page.locator("#target").click()
- assert before_count == args[1]
- assert after_count == args[1]
- assert await page.evaluate("window.clicked") == 1
- await expect(page.locator("#interstitial")).not_to_be_visible()
-
-
-async def test_should_work_with_a_custom_check(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/handle-locator.html")
-
- async def handler() -> None:
- if await page.get_by_text("This interstitial covers the button").is_visible():
- await page.locator("#close").click()
-
- await page.add_locator_handler(page.locator("body"), handler, no_wait_after=True)
-
- for args in [
- ["mouseover", 2],
- ["none", 1],
- ["remove", 1],
- ["hide", 1],
- ]:
- await page.locator("#aside").hover()
- await page.evaluate(
- "(args) => { window.clicked = 0; window.setupAnnoyingInterstitial(...args); }",
- args,
- )
- await page.locator("#target").click()
- assert await page.evaluate("window.clicked") == 1
- await expect(page.locator("#interstitial")).not_to_be_visible()
-
-
-async def test_should_work_with_locator_hover(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/handle-locator.html")
-
- await page.add_locator_handler(
- page.get_by_text("This interstitial covers the button"),
- lambda: page.locator("#close").click(),
- )
-
- await page.locator("#aside").hover()
- await page.evaluate('() => { window.setupAnnoyingInterstitial("pointerover", 1, "capture"); }')
- await page.locator("#target").hover()
- await expect(page.locator("#interstitial")).not_to_be_visible()
- assert (
- await page.eval_on_selector("#target", "e => window.getComputedStyle(e).backgroundColor")
- == "rgb(255, 255, 0)"
- )
-
-
-async def test_should_not_work_with_force_true(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/handle-locator.html")
-
- await page.add_locator_handler(
- page.get_by_text("This interstitial covers the button"),
- lambda: page.locator("#close").click(),
- )
-
- await page.locator("#aside").hover()
- await page.evaluate('() => { window.setupAnnoyingInterstitial("none", 1); }')
- await page.locator("#target").click(force=True, timeout=2000)
- assert await page.locator("#interstitial").is_visible()
- assert await page.evaluate("window.clicked") is None
-
-
-async def test_should_throw_when_page_closes(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/handle-locator.html")
-
- await page.add_locator_handler(
- page.get_by_text("This interstitial covers the button"), lambda: page.close()
- )
-
- await page.locator("#aside").hover()
- await page.evaluate(
- '() => { window.clicked = 0; window.setupAnnoyingInterstitial("mouseover", 1); }'
- )
- with pytest.raises(Error) as exc:
- await page.locator("#target").click()
- assert TARGET_CLOSED_ERROR_MESSAGE in exc.value.message
-
-
-async def test_should_throw_when_handler_times_out(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/handle-locator.html")
-
- called = 0
- stall_future: asyncio.Future[None] = asyncio.Future()
-
- async def handler() -> None:
- nonlocal called
- called += 1
- # Deliberately timeout.
- await stall_future
-
- await page.add_locator_handler(page.get_by_text("This interstitial covers the button"), handler)
-
- await page.locator("#aside").hover()
- await page.evaluate(
- '() => { window.clicked = 0; window.setupAnnoyingInterstitial("mouseover", 1); }'
- )
- with pytest.raises(Error) as exc:
- await page.locator("#target").click(timeout=3000)
- assert "Timeout 3000ms exceeded" in exc.value.message
-
- with pytest.raises(Error) as exc:
- await page.locator("#target").click(timeout=3000)
- assert "Timeout 3000ms exceeded" in exc.value.message
-
- # Should not enter the same handler while it is still running.
- assert called == 1
- stall_future.cancel()
-
-
-async def test_should_work_with_to_be_visible(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/handle-locator.html")
-
- called = 0
-
- async def handler() -> None:
- nonlocal called
- called += 1
- await page.locator("#close").click()
-
- await page.add_locator_handler(page.get_by_text("This interstitial covers the button"), handler)
-
- await page.evaluate(
- '() => { window.clicked = 0; window.setupAnnoyingInterstitial("remove", 1); }'
- )
- await expect(page.locator("#target")).to_be_visible()
- await expect(page.locator("#interstitial")).not_to_be_visible()
- assert called == 1
-
-
-async def test_should_work_when_owner_frame_detaches(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- await page.evaluate(
- """
- () => {
- const iframe = document.createElement('iframe');
- iframe.src = 'data:text/html,hello from iframe';
- document.body.append(iframe);
-
- const target = document.createElement('button');
- target.textContent = 'Click me';
- target.id = 'target';
- target.addEventListener('click', () => window._clicked = true);
- document.body.appendChild(target);
-
- const closeButton = document.createElement('button');
- closeButton.textContent = 'close';
- closeButton.id = 'close';
- closeButton.addEventListener('click', () => iframe.remove());
- document.body.appendChild(closeButton);
- }
- """
- )
- await page.add_locator_handler(
- page.frame_locator("iframe").locator("body"),
- lambda: page.locator("#close").click(),
- )
- await page.locator("#target").click()
- assert await page.query_selector("iframe") is None
- assert await page.evaluate("window._clicked") is True
-
-
-async def test_should_work_with_times_option(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/handle-locator.html")
- called = 0
-
- def _handler() -> None:
- nonlocal called
- called += 1
-
- await page.add_locator_handler(page.locator("body"), _handler, no_wait_after=True, times=2)
- await page.locator("#aside").hover()
- await page.evaluate(
- """
- () => {
- window.clicked = 0;
- window.setupAnnoyingInterstitial('mouseover', 4);
- }
- """
- )
- with pytest.raises(Error) as exc_info:
- await page.locator("#target").click(timeout=3000)
- assert called == 2
- assert await page.evaluate("window.clicked") == 0
- await expect(page.locator("#interstitial")).to_be_visible()
- assert "Timeout 3000ms exceeded" in exc_info.value.message
- assert (
- 'This interstitial covers the button
from …
subtree intercepts pointer events'
- in exc_info.value.message
- )
-
-
-async def test_should_wait_for_hidden_by_default(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/handle-locator.html")
- called = 0
-
- async def _handler(button: Locator) -> None:
- nonlocal called
- called += 1
- await button.click()
-
- await page.add_locator_handler(page.get_by_role("button", name="close"), _handler)
- await page.locator("#aside").hover()
- await page.evaluate(
- """
- () => {
- window.clicked = 0;
- window.setupAnnoyingInterstitial('timeout', 1);
- }
- """
- )
- await page.locator("#target").click()
- assert await page.evaluate("window.clicked") == 1
- await expect(page.locator("#interstitial")).not_to_be_visible()
- assert called == 1
-
-
-async def test_should_wait_for_hidden_by_default_2(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/handle-locator.html")
- called = 0
-
- def _handler() -> None:
- nonlocal called
- called += 1
-
- await page.add_locator_handler(page.get_by_role("button", name="close"), _handler)
- await page.locator("#aside").hover()
- await page.evaluate(
- """
- () => {
- window.clicked = 0;
- window.setupAnnoyingInterstitial('hide', 1);
- }
- """
- )
- with pytest.raises(Error) as exc_info:
- await page.locator("#target").click(timeout=3000)
- assert await page.evaluate("window.clicked") == 0
- await expect(page.locator("#interstitial")).to_be_visible()
- assert called == 1
- assert (
- 'locator handler has finished, waiting for get_by_role("button", name="close") to be hidden'
- in exc_info.value.message
- )
-
-
-async def test_should_work_with_noWaitAfter(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/handle-locator.html")
- called = 0
-
- async def _handler(button: Locator) -> None:
- nonlocal called
- called += 1
- if called == 1:
- await button.click()
- else:
- await page.locator("#interstitial").wait_for(state="hidden")
-
- await page.add_locator_handler(
- page.get_by_role("button", name="close"), _handler, no_wait_after=True
- )
- await page.locator("#aside").hover()
- await page.evaluate(
- """
- () => {
- window.clicked = 0;
- window.setupAnnoyingInterstitial('timeout', 1);
- }
- """
- )
- await page.locator("#target").click()
- assert await page.evaluate("window.clicked") == 1
- await expect(page.locator("#interstitial")).not_to_be_visible()
- assert called == 2
-
-
-async def test_should_removeLocatorHandler(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/handle-locator.html")
- called = 0
-
- async def _handler(locator: Locator) -> None:
- nonlocal called
- called += 1
- await locator.click()
-
- await page.add_locator_handler(page.get_by_role("button", name="close"), _handler)
- await page.evaluate(
- """
- () => {
- window.clicked = 0;
- window.setupAnnoyingInterstitial('hide', 1);
- }
- """
- )
- await page.locator("#target").click()
- assert called == 1
- assert await page.evaluate("window.clicked") == 1
- await expect(page.locator("#interstitial")).not_to_be_visible()
- await page.evaluate(
- """
- () => {
- window.clicked = 0;
- window.setupAnnoyingInterstitial('hide', 1);
- }
- """
- )
- await page.remove_locator_handler(page.get_by_role("button", name="close"))
- with pytest.raises(Error) as error:
- await page.locator("#target").click(timeout=3000)
- assert called == 1
- assert await page.evaluate("window.clicked") == 0
- await expect(page.locator("#interstitial")).to_be_visible()
- assert "Timeout 3000ms exceeded" in error.value.message
diff --git a/tests/async/test_page_base_url.py b/tests/async/test_page_base_url.py
deleted file mode 100644
index bcf1cc1..0000000
--- a/tests/async/test_page_base_url.py
+++ /dev/null
@@ -1,114 +0,0 @@
-# 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.
-
-from pathlib import Path
-from typing import Dict
-
-from playwright.async_api import Browser, BrowserType
-from tests.server import Server
-from tests.utils import must
-
-
-async def test_should_construct_a_new_url_when_a_base_url_in_browser_new_context_is_passed(
- browser: Browser, server: Server
-) -> None:
- context = await browser.new_context(base_url=server.PREFIX)
- page = await context.new_page()
- assert (must(await page.goto("/empty.html"))).url == server.EMPTY_PAGE
- await context.close()
-
-
-async def test_should_construct_a_new_url_when_a_base_url_in_browser_new_page_is_passed(
- browser: Browser, server: Server
-) -> None:
- page = await browser.new_page(base_url=server.PREFIX)
- assert (must(await page.goto("/empty.html"))).url == server.EMPTY_PAGE
- await page.close()
-
-
-async def test_should_construct_a_new_url_when_a_base_url_in_browser_new_persistent_context_is_passed(
- browser_type: BrowserType, tmpdir: Path, server: Server, launch_arguments: Dict
-) -> None:
- context = await browser_type.launch_persistent_context(
- tmpdir, **launch_arguments, base_url=server.PREFIX
- )
- page = await context.new_page()
- assert (must(await page.goto("/empty.html"))).url == server.EMPTY_PAGE
- await context.close()
-
-
-async def test_should_construct_correctly_when_a_baseurl_without_a_trailing_slash_is_passed(
- browser: Browser, server: Server
-) -> None:
- page = await browser.new_page(base_url=server.PREFIX + "/url-construction")
- assert (must(await page.goto("mypage.html"))).url == server.PREFIX + "/mypage.html"
- assert (must(await page.goto("./mypage.html"))).url == server.PREFIX + "/mypage.html"
- assert (must(await page.goto("/mypage.html"))).url == server.PREFIX + "/mypage.html"
- await page.close()
-
-
-async def test_should_construct_correctly_when_a_baseurl_with_a_trailing_slash_is_passed(
- browser: Browser, server: Server
-) -> None:
- page = await browser.new_page(base_url=server.PREFIX + "/url-construction/")
- assert (
- must(await page.goto("mypage.html"))
- ).url == server.PREFIX + "/url-construction/mypage.html"
- assert (
- must(await page.goto("./mypage.html"))
- ).url == server.PREFIX + "/url-construction/mypage.html"
- assert (must(await page.goto("/mypage.html"))).url == server.PREFIX + "/mypage.html"
- assert (must(await page.goto("."))).url == server.PREFIX + "/url-construction/"
- assert (must(await page.goto("/"))).url == server.PREFIX + "/"
- await page.close()
-
-
-async def test_should_not_construct_a_new_url_when_valid_urls_are_passed(
- browser: Browser, server: Server
-) -> None:
- page = await browser.new_page(base_url="http://microsoft.com")
- response = await page.goto(server.EMPTY_PAGE)
- assert response
- assert response.url == server.EMPTY_PAGE
-
- await page.goto("data:text/html,Hello world")
- assert page.url == "data:text/html,Hello world"
-
- await page.goto("about:blank")
- assert page.url == "about:blank"
-
- await page.close()
-
-
-async def test_should_be_able_to_match_a_url_relative_to_its_given_url_with_urlmatcher(
- browser: Browser, server: Server
-) -> None:
- page = await browser.new_page(base_url=server.PREFIX + "/foobar/")
-
- await page.goto("/kek/index.html")
- await page.wait_for_url("/kek/index.html")
- assert page.url == server.PREFIX + "/kek/index.html"
-
- await page.route("./kek/index.html", lambda route: route.fulfill(body="base-url-matched-route"))
-
- async with page.expect_request("./kek/index.html") as request_info:
- async with page.expect_response("./kek/index.html") as response_info:
- await page.goto("./kek/index.html")
- request = await request_info.value
- response = await response_info.value
- assert request.url == server.PREFIX + "/foobar/kek/index.html"
- assert response.url == server.PREFIX + "/foobar/kek/index.html"
- assert await response.body() == b"base-url-matched-route"
-
- await page.close()
diff --git a/tests/async/test_page_clock.py b/tests/async/test_page_clock.py
deleted file mode 100644
index e6bb948..0000000
--- a/tests/async/test_page_clock.py
+++ /dev/null
@@ -1,462 +0,0 @@
-# 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 datetime
-from typing import Any, AsyncGenerator, List
-
-import pytest
-
-from playwright.async_api import Error, Page
-from tests.server import Server
-
-
-@pytest.fixture(autouse=True)
-async def calls(page: Page) -> List[Any]:
- calls: List[Any] = []
- await page.expose_function("stub", lambda *args: calls.append(list(args)))
- return calls
-
-
-class TestRunFor:
- @pytest.fixture(autouse=True)
- async def before_each(self, page: Page) -> AsyncGenerator[None, None]:
- await page.clock.install(time=0)
- await page.clock.pause_at(1000)
- yield
-
- async def test_run_for_triggers_immediately_without_specified_delay(
- self, page: Page, calls: List[Any]
- ) -> None:
- await page.evaluate("setTimeout(window.stub)")
- await page.clock.run_for(0)
- assert len(calls) == 1
-
- async def test_run_for_does_not_trigger_without_sufficient_delay(
- self, page: Page, calls: List[Any]
- ) -> None:
- await page.evaluate("setTimeout(window.stub, 100)")
- await page.clock.run_for(10)
- assert len(calls) == 0
-
- async def test_run_for_triggers_after_sufficient_delay(
- self, page: Page, calls: List[Any]
- ) -> None:
- await page.evaluate("setTimeout(window.stub, 100)")
- await page.clock.run_for(100)
- assert len(calls) == 1
-
- async def test_run_for_triggers_simultaneous_timers(self, page: Page, calls: List[Any]) -> None:
- await page.evaluate("setTimeout(window.stub, 100); setTimeout(window.stub, 100)")
- await page.clock.run_for(100)
- assert len(calls) == 2
-
- async def test_run_for_triggers_multiple_simultaneous_timers(
- self, page: Page, calls: List[Any]
- ) -> None:
- await page.evaluate(
- "setTimeout(window.stub, 100); setTimeout(window.stub, 100); setTimeout(window.stub, 99); setTimeout(window.stub, 100)"
- )
- await page.clock.run_for(100)
- assert len(calls) == 4
-
- async def test_run_for_waits_after_setTimeout_was_called(
- self, page: Page, calls: List[Any]
- ) -> None:
- await page.evaluate("setTimeout(window.stub, 150)")
- await page.clock.run_for(50)
- assert len(calls) == 0
- await page.clock.run_for(100)
- assert len(calls) == 1
-
- async def test_run_for_triggers_event_when_some_throw(
- self, page: Page, calls: List[Any]
- ) -> None:
- await page.evaluate(
- "setTimeout(() => { throw new Error(); }, 100); setTimeout(window.stub, 120)"
- )
- with pytest.raises(Error):
- await page.clock.run_for(120)
- assert len(calls) == 1
-
- async def test_run_for_creates_updated_Date_while_ticking(
- self, page: Page, calls: List[Any]
- ) -> None:
- await page.clock.set_system_time(0)
- await page.evaluate("setInterval(() => { window.stub(new Date().getTime()); }, 10)")
- await page.clock.run_for(100)
- assert calls == [
- [10],
- [20],
- [30],
- [40],
- [50],
- [60],
- [70],
- [80],
- [90],
- [100],
- ]
-
- async def test_run_for_passes_8_seconds(self, page: Page, calls: List[Any]) -> None:
- await page.evaluate("setInterval(window.stub, 4000)")
- await page.clock.run_for("08")
- assert len(calls) == 2
-
- async def test_run_for_passes_1_minute(self, page: Page, calls: List[Any]) -> None:
- await page.evaluate("setInterval(window.stub, 6000)")
- await page.clock.run_for("01:00")
- assert len(calls) == 10
-
- async def test_run_for_passes_2_hours_34_minutes_and_10_seconds(
- self, page: Page, calls: List[Any]
- ) -> None:
- await page.evaluate("setInterval(window.stub, 10000)")
- await page.clock.run_for("02:34:10")
- assert len(calls) == 925
-
- async def test_run_for_throws_for_invalid_format(self, page: Page, calls: List[Any]) -> None:
- await page.evaluate("setInterval(window.stub, 10000)")
- with pytest.raises(Error):
- await page.clock.run_for("12:02:34:10")
- assert len(calls) == 0
-
- async def test_run_for_returns_the_current_now_value(self, page: Page) -> None:
- await page.clock.set_system_time(0)
- value = 200
- await page.clock.run_for(value)
- assert await page.evaluate("Date.now()") == value
-
-
-class TestFastForward:
- @pytest.fixture(autouse=True)
- async def before_each(self, page: Page) -> AsyncGenerator[None, None]:
- await page.clock.install(time=0)
- await page.clock.pause_at(1)
- yield
-
- async def test_ignores_timers_which_wouldnt_be_run(self, page: Page, calls: List[Any]) -> None:
- await page.evaluate("setTimeout(() => { window.stub('should not be logged'); }, 1000)")
- await page.clock.fast_forward(500)
- assert len(calls) == 0
-
- async def test_pushes_back_execution_time_for_skipped_timers(
- self, page: Page, calls: List[Any]
- ) -> None:
- await page.evaluate("setTimeout(() => { window.stub(Date.now()); }, 1000)")
- await page.clock.fast_forward(2000)
- assert calls == [[1000 + 2000]]
-
- async def test_supports_string_time_arguments(self, page: Page, calls: List[Any]) -> None:
- await page.evaluate(
- "setTimeout(() => { window.stub(Date.now()); }, 100000)"
- ) # 100000 = 1:40
- await page.clock.fast_forward("01:50")
- assert calls == [[1000 + 110000]]
-
-
-class TestStubTimers:
- @pytest.fixture(autouse=True)
- async def before_each(self, page: Page) -> AsyncGenerator[None, None]:
- await page.clock.install(time=0)
- await page.clock.pause_at(1)
- yield
-
- async def test_sets_initial_timestamp(self, page: Page) -> None:
- await page.clock.set_system_time(1.4)
- assert await page.evaluate("Date.now()") == 1400
-
- async def test_replaces_global_setTimeout(self, page: Page, calls: List[Any]) -> None:
- await page.evaluate("setTimeout(window.stub, 1000)")
- await page.clock.run_for(1000)
- assert len(calls) == 1
-
- async def test_global_fake_setTimeout_should_return_id(self, page: Page) -> None:
- to = await page.evaluate("setTimeout(window.stub, 1000)")
- assert isinstance(to, int)
-
- async def test_replaces_global_clearTimeout(self, page: Page, calls: List[Any]) -> None:
- await page.evaluate(
- """
- const to = setTimeout(window.stub, 1000);
- clearTimeout(to);
- """
- )
- await page.clock.run_for(1000)
- assert len(calls) == 0
-
- async def test_replaces_global_setInterval(self, page: Page, calls: List[Any]) -> None:
- await page.evaluate("setInterval(window.stub, 500)")
- await page.clock.run_for(1000)
- assert len(calls) == 2
-
- async def test_replaces_global_clearInterval(self, page: Page, calls: List[Any]) -> None:
- await page.evaluate(
- """
- const to = setInterval(window.stub, 500);
- clearInterval(to);
- """
- )
- await page.clock.run_for(1000)
- assert len(calls) == 0
-
- async def test_replaces_global_performance_now(self, page: Page) -> None:
- promise = asyncio.create_task(
- page.evaluate(
- """async () => {
- const prev = performance.now();
- await new Promise(f => setTimeout(f, 1000));
- const next = performance.now();
- return { prev, next };
- }"""
- )
- )
- await asyncio.sleep(0) # Make sure the promise is scheduled.
- await page.clock.run_for(1000)
- assert await promise == {"prev": 1000, "next": 2000}
-
- async def test_fakes_Date_constructor(self, page: Page) -> None:
- now = await page.evaluate("new Date().getTime()")
- assert now == 1000
-
-
-class TestStubTimersPerformance:
- async def test_replaces_global_performance_time_origin(self, page: Page) -> None:
- await page.clock.install(time=1)
- await page.clock.pause_at(2)
- promise = asyncio.create_task(
- page.evaluate(
- """async () => {
- const prev = performance.now();
- await new Promise(f => setTimeout(f, 1000));
- const next = performance.now();
- return { prev, next };
- }"""
- )
- )
- await asyncio.sleep(0) # Make sure the promise is scheduled.
- await page.clock.run_for(1000)
- assert await page.evaluate("performance.timeOrigin") == 1000
- assert await promise == {"prev": 1000, "next": 2000}
-
-
-class TestPopup:
- async def test_should_tick_after_popup(self, page: Page) -> None:
- await page.clock.install(time=0)
- now = datetime.datetime.fromisoformat("2015-09-25")
- await page.clock.pause_at(now)
- popup, _ = await asyncio.gather(
- page.wait_for_event("popup"), page.evaluate("window.open('about:blank')")
- )
- popup_time = await popup.evaluate("Date.now()")
- assert popup_time == now.timestamp() * 1000
- await page.clock.run_for(1000)
- popup_time_after = await popup.evaluate("Date.now()")
- assert popup_time_after == now.timestamp() * 1000 + 1000
-
- async def test_should_tick_before_popup(self, page: Page) -> None:
- await page.clock.install(time=0)
- now = datetime.datetime.fromisoformat("2015-09-25")
- await page.clock.pause_at(now)
- await page.clock.run_for(1000)
- popup, _ = await asyncio.gather(
- page.wait_for_event("popup"), page.evaluate("window.open('about:blank')")
- )
- popup_time = await popup.evaluate("Date.now()")
- assert popup_time == int(now.timestamp() * 1000 + 1000)
- assert datetime.datetime.fromtimestamp(popup_time / 1_000).year == 2015
-
- async def test_should_run_time_before_popup(self, page: Page, server: Server) -> None:
- server.set_route(
- "/popup.html",
- lambda res: (
- res.setHeader("Content-Type", "text/html"),
- res.write(b""),
- res.finish(),
- ),
- )
- await page.goto(server.EMPTY_PAGE)
- # Wait for 2 second in real life to check that it is past in popup.
- await page.wait_for_timeout(2000)
- popup, _ = await asyncio.gather(
- page.wait_for_event("popup"),
- page.evaluate("window.open('{}')".format(server.PREFIX + "/popup.html")),
- )
- popup_time = await popup.evaluate("window.time")
- assert popup_time >= 2000
-
- async def test_should_not_run_time_before_popup_on_pause(
- self, page: Page, server: Server
- ) -> None:
- server.set_route(
- "/popup.html",
- lambda res: (
- res.setHeader("Content-Type", "text/html"),
- res.write(b""),
- res.finish(),
- ),
- )
- await page.clock.install(time=0)
- await page.clock.pause_at(1)
- await page.goto(server.EMPTY_PAGE)
- # Wait for 2 second in real life to check that it is past in popup.
- await page.wait_for_timeout(2000)
- popup, _ = await asyncio.gather(
- page.wait_for_event("popup"),
- page.evaluate("window.open('{}')".format(server.PREFIX + "/popup.html")),
- )
- popup_time = await popup.evaluate("window.time")
- assert popup_time == 1000
-
-
-class TestSetFixedTime:
- async def test_does_not_fake_methods(self, page: Page) -> None:
- await page.clock.set_fixed_time(0)
- # Should not stall.
- await page.evaluate("new Promise(f => setTimeout(f, 1))")
-
- async def test_allows_setting_time_multiple_times(self, page: Page) -> None:
- await page.clock.set_fixed_time(0.1)
- assert await page.evaluate("Date.now()") == 100
- await page.clock.set_fixed_time(0.2)
- assert await page.evaluate("Date.now()") == 200
-
- async def test_fixed_time_is_not_affected_by_clock_manipulation(self, page: Page) -> None:
- await page.clock.set_fixed_time(0.1)
- assert await page.evaluate("Date.now()") == 100
- await page.clock.fast_forward(20)
- assert await page.evaluate("Date.now()") == 100
-
- async def test_allows_installing_fake_timers_after_setting_time(
- self, page: Page, calls: List[Any]
- ) -> None:
- await page.clock.set_fixed_time(0.1)
- assert await page.evaluate("Date.now()") == 100
- await page.clock.set_fixed_time(0.2)
- await page.evaluate("setTimeout(() => window.stub(Date.now()))")
- await page.clock.run_for(0)
- assert calls == [[200]]
-
-
-class TestWhileRunning:
- async def test_should_progress_time(self, page: Page) -> None:
- await page.clock.install(time=0)
- await page.goto("data:text/html,")
- await page.wait_for_timeout(1000)
- now = await page.evaluate("Date.now()")
- assert 1000 <= now <= 2000
-
- async def test_should_run_for(self, page: Page) -> None:
- await page.clock.install(time=0)
- await page.goto("data:text/html,")
- await page.clock.run_for(10000)
- now = await page.evaluate("Date.now()")
- assert 10000 <= now <= 11000
-
- async def test_should_fast_forward(self, page: Page) -> None:
- await page.clock.install(time=0)
- await page.goto("data:text/html,")
- await page.clock.fast_forward(10000)
- now = await page.evaluate("Date.now()")
- assert 10000 <= now <= 11000
-
- async def test_should_fast_forward_to(self, page: Page) -> None:
- await page.clock.install(time=0)
- await page.goto("data:text/html,")
- await page.clock.fast_forward(10000)
- now = await page.evaluate("Date.now()")
- assert 10000 <= now <= 11000
-
- async def test_should_pause(self, page: Page) -> None:
- await page.clock.install(time=0)
- await page.goto("data:text/html,")
- await page.clock.pause_at(1)
- await page.wait_for_timeout(1000)
- await page.clock.resume()
- now = await page.evaluate("Date.now()")
- assert 0 <= now <= 1000
-
- async def test_should_pause_and_fast_forward(self, page: Page) -> None:
- await page.clock.install(time=0)
- await page.goto("data:text/html,")
- await page.clock.pause_at(1)
- await page.clock.fast_forward(1000)
- now = await page.evaluate("Date.now()")
- assert now == 2000
-
- async def test_should_set_system_time_on_pause(self, page: Page) -> None:
- await page.clock.install(time=0)
- await page.goto("data:text/html,")
- await page.clock.pause_at(1)
- now = await page.evaluate("Date.now()")
- assert now == 1000
-
-
-class TestWhileOnPause:
- async def test_fast_forward_should_not_run_nested_immediate(
- self, page: Page, calls: List[Any]
- ) -> None:
- await page.clock.install(time=0)
- await page.goto("data:text/html,")
- await page.clock.pause_at(1000)
- await page.evaluate(
- """
- setTimeout(() => {
- window.stub('outer');
- setTimeout(() => window.stub('inner'), 0);
- }, 1000);
- """
- )
- await page.clock.fast_forward(1000)
- assert calls == [["outer"]]
- await page.clock.fast_forward(1)
- assert calls == [["outer"], ["inner"]]
-
- async def test_run_for_should_not_run_nested_immediate(
- self, page: Page, calls: List[Any]
- ) -> None:
- await page.clock.install(time=0)
- await page.goto("data:text/html,")
- await page.clock.pause_at(1000)
- await page.evaluate(
- """
- setTimeout(() => {
- window.stub('outer');
- setTimeout(() => window.stub('inner'), 0);
- }, 1000);
- """
- )
- await page.clock.run_for(1000)
- assert calls == [["outer"]]
- await page.clock.run_for(1)
- assert calls == [["outer"], ["inner"]]
-
- async def test_run_for_should_not_run_nested_immediate_from_microtask(
- self, page: Page, calls: List[Any]
- ) -> None:
- await page.clock.install(time=0)
- await page.goto("data:text/html,")
- await page.clock.pause_at(1000)
- await page.evaluate(
- """
- setTimeout(() => {
- window.stub('outer');
- void Promise.resolve().then(() => setTimeout(() => window.stub('inner'), 0));
- }, 1000);
- """
- )
- await page.clock.run_for(1000)
- assert calls == [["outer"]]
- await page.clock.run_for(1)
- assert calls == [["outer"], ["inner"]]
diff --git a/tests/async/test_page_evaluate.py b/tests/async/test_page_evaluate.py
deleted file mode 100644
index 9b3e4c1..0000000
--- a/tests/async/test_page_evaluate.py
+++ /dev/null
@@ -1,320 +0,0 @@
-# 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 math
-from datetime import datetime, timedelta, timezone
-from typing import Optional
-from urllib.parse import ParseResult, urlparse
-
-from playwright.async_api import Error, Page
-
-
-async def test_evaluate_work(page: Page) -> None:
- result = await page.evaluate("7 * 3")
- assert result == 21
-
-
-async def test_evaluate_return_none_for_null(page: Page) -> None:
- result = await page.evaluate("a => a", None)
- assert result is None
-
-
-async def test_evaluate_transfer_nan(page: Page) -> None:
- result = await page.evaluate("a => a", float("nan"))
- assert math.isnan(result)
-
-
-async def test_evaluate_transfer_neg_zero(page: Page) -> None:
- result = await page.evaluate("a => a", -0)
- assert result == float("-0")
-
-
-async def test_evaluate_transfer_infinity(page: Page) -> None:
- result = await page.evaluate("a => a", float("Infinity"))
- assert result == float("Infinity")
-
-
-async def test_evaluate_transfer_neg_infinity(page: Page) -> None:
- result = await page.evaluate("a => a", float("-Infinity"))
- assert result == float("-Infinity")
-
-
-async def test_evaluate_roundtrip_unserializable_values(page: Page) -> None:
- value = {
- "infinity": float("Infinity"),
- "nInfinity": float("-Infinity"),
- "nZero": float("-0"),
- }
- result = await page.evaluate("a => a", value)
- assert result == value
-
-
-async def test_evaluate_transfer_arrays(page: Page) -> None:
- result = await page.evaluate("a => a", [1, 2, 3])
- assert result == [1, 2, 3]
-
-
-async def test_evaluate_transfer_bigint(page: Page) -> None:
- assert await page.evaluate("() => 42n") == 42
- assert await page.evaluate("a => a", 17) == 17
-
-
-async def test_evaluate_return_undefined_for_objects_with_symbols(page: Page) -> None:
- assert await page.evaluate('[Symbol("foo4")]') == [None]
- assert (
- await page.evaluate(
- """() => {
- const a = { };
- a[Symbol('foo4')] = 42;
- return a;
- }"""
- )
- == {}
- )
- assert (
- await page.evaluate(
- """() => {
- return { foo: [{ a: Symbol('foo4') }] };
- }"""
- )
- == {"foo": [{"a": None}]}
- )
-
-
-async def test_evaluate_work_with_unicode_chars(page: Page) -> None:
- result = await page.evaluate('a => a["中文字符"]', {"中文字符": 42})
- assert result == 42
-
-
-async def test_evaluate_throw_when_evaluation_triggers_reload(page: Page) -> None:
- error: Optional[Error] = None
- try:
- await page.evaluate("() => { location.reload(); return new Promise(() => {}); }")
- except Error as e:
- error = e
- assert error
- assert "navigation" in error.message
-
-
-async def test_evaluate_work_with_exposed_function(page: Page) -> None:
- await page.expose_function("callController", lambda a, b: a * b)
- result = await page.evaluate("callController(9, 3)")
- assert result == 27
-
-
-async def test_evaluate_reject_promise_with_exception(page: Page) -> None:
- error: Optional[Error] = None
- try:
- await page.evaluate("not_existing_object.property")
- except Error as e:
- error = e
- assert error
- assert "not_existing_object" in error.message
-
-
-async def test_evaluate_support_thrown_strings(page: Page) -> None:
- error: Optional[Error] = None
- try:
- await page.evaluate('throw "qwerty"')
- except Error as e:
- error = e
- assert error
- assert "qwerty" in error.message
-
-
-async def test_evaluate_support_thrown_numbers(page: Page) -> None:
- error: Optional[Error] = None
- try:
- await page.evaluate("throw 100500")
- except Error as e:
- error = e
- assert error
- assert "100500" in error.message
-
-
-async def test_evaluate_return_complex_objects(page: Page) -> None:
- obj = {"foo": "bar!"}
- result = await page.evaluate("a => a", obj)
- assert result == obj
-
-
-async def test_evaluate_accept_none_as_one_of_multiple_parameters(page: Page) -> None:
- result = await page.evaluate(
- '({ a, b }) => Object.is(a, null) && Object.is(b, "foo")',
- {"a": None, "b": "foo"},
- )
- assert result
-
-
-async def test_evaluate_properly_serialize_none_arguments(page: Page) -> None:
- assert await page.evaluate("x => ({a: x})", None) == {"a": None}
-
-
-async def test_should_alias_window_document_and_node(page: Page) -> None:
- object = await page.evaluate("[window, document, document.body]")
- assert object == ["ref: ", "ref: ", "ref: "]
-
-
-async def test_evaluate_should_work_for_circular_object(page: Page) -> None:
- a = await page.evaluate(
- """() => {
- const a = {x: 47};
- const b = {a};
- a.b = b;
- return a;
- }"""
- )
-
- assert a["b"]["a"]["b"]["a"]["x"] == 47
- assert a["b"]["a"] == a
-
-
-async def test_evaluate_accept_string(page: Page) -> None:
- assert await page.evaluate("1 + 2") == 3
-
-
-async def test_evaluate_accept_element_handle_as_an_argument(page: Page) -> None:
- await page.set_content("")
- element = await page.query_selector("section")
- text = await page.evaluate("e => e.textContent", element)
- assert text == "42"
-
-
-async def test_evaluate_throw_if_underlying_element_was_disposed(page: Page) -> None:
- await page.set_content("")
- element = await page.query_selector("section")
- assert element
- await element.dispose()
- error: Optional[Error] = None
- try:
- await page.evaluate("e => e.textContent", element)
- except Error as e:
- error = e
- assert error
- assert "no object with guid" in error.message
-
-
-async def test_evaluate_evaluate_exception(page: Page) -> None:
- error = await page.evaluate(
- """() => {
- function innerFunction() {
- const e = new Error('error message');
- e.name = 'foobar';
- return e;
- }
- return innerFunction();
- }"""
- )
- assert isinstance(error, Error)
- assert error.message == "error message"
- assert error.name == "foobar"
- assert error.stack
- assert "innerFunction" in error.stack
-
-
-async def test_should_pass_exception_argument(page: Page) -> None:
- def _raise_and_get_exception(exception: Exception) -> Exception:
- try:
- raise exception
- except Exception as e:
- return e
-
- error_for_roundtrip = Error("error message")
- error_for_roundtrip._name = "foobar"
- error_for_roundtrip._stack = "test stack"
- error = await page.evaluate(
- """e => {
- return { message: e.message, name: e.name, stack: e.stack };
- }""",
- error_for_roundtrip,
- )
- assert error["message"] == "error message"
- assert error["name"] == "foobar"
- assert "test stack" in error["stack"]
-
- error = await page.evaluate(
- """e => {
- return { message: e.message, name: e.name, stack: e.stack };
- }""",
- _raise_and_get_exception(Exception("error message")),
- )
- assert error["message"] == "error message"
- assert error["name"] == "Exception"
- assert "error message" in error["stack"]
-
-
-async def test_evaluate_evaluate_date(page: Page) -> None:
- result = await page.evaluate('() => ({ date: new Date("2020-05-27T01:31:38.506Z") })')
- assert result == {
- "date": datetime.fromisoformat("2020-05-27T01:31:38.506").replace(tzinfo=timezone.utc)
- }
-
-
-async def test_evaluate_roundtrip_date_without_tzinfo(page: Page) -> None:
- date = datetime.fromisoformat("2020-05-27T01:31:38.506")
- result = await page.evaluate("date => date", date)
- assert result.timestamp() == date.timestamp()
-
-
-async def test_evaluate_roundtrip_date(page: Page) -> None:
- date = datetime.fromisoformat("2020-05-27T01:31:38.506").replace(tzinfo=timezone.utc)
- result = await page.evaluate("date => date", date)
- assert result == date
-
-
-async def test_evaluate_roundtrip_date_with_tzinfo(page: Page) -> None:
- date = datetime.fromisoformat("2020-05-27T01:31:38.506")
- date = date.astimezone(timezone(timedelta(hours=4)))
- result = await page.evaluate("date => date", date)
- assert result == date
-
-
-async def test_evaluate_jsonvalue_date(page: Page) -> None:
- date = datetime.fromisoformat("2020-05-27T01:31:38.506").replace(tzinfo=timezone.utc)
- result = await page.evaluate('() => ({ date: new Date("2020-05-27T01:31:38.506Z") })')
- assert result == {"date": date}
-
-
-async def test_should_evaluate_url(page: Page) -> None:
- out = await page.evaluate(
- "() => ({ someKey: new URL('https://user:pass@example.com/?foo=bar#hi') })"
- )
- assert out["someKey"] == ParseResult(
- scheme="https",
- netloc="user:pass@example.com",
- path="/",
- query="foo=bar",
- params="",
- fragment="hi",
- )
-
-
-async def test_should_roundtrip_url(page: Page) -> None:
- in_ = urlparse("https://user:pass@example.com/?foo=bar#hi")
- out = await page.evaluate("url => url", in_)
- assert in_ == out
-
-
-async def test_should_roundtrip_complex_url(page: Page) -> None:
- in_ = urlparse(
- "https://user:password@www.contoso.com:80/Home/Index.htm?q1=v1&q2=v2#FragmentName"
- )
- out = await page.evaluate("url => url", in_)
- assert in_ == out
-
-
-async def test_evaluate_jsonvalue_url(page: Page) -> None:
- url = urlparse("https://example.com/")
- result = await page.evaluate('() => ({ someKey: new URL("https://example.com/") })')
- assert result == {"someKey": url}
diff --git a/tests/async/test_page_network_request.py b/tests/async/test_page_network_request.py
deleted file mode 100644
index 61fe65f..0000000
--- a/tests/async/test_page_network_request.py
+++ /dev/null
@@ -1,61 +0,0 @@
-# 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 Error, Page, Request
-from tests.server import Server
-
-
-async def test_should_not_allow_to_access_frame_on_popup_main_request(
- page: Page, server: Server
-) -> None:
- await page.set_content(f'click me ')
- request_promise = asyncio.ensure_future(page.context.wait_for_event("request"))
- popup_promise = asyncio.ensure_future(page.context.wait_for_event("page"))
- clicked = asyncio.ensure_future(page.get_by_text("click me").click())
- request: Request = await request_promise
-
- assert request.is_navigation_request()
-
- with pytest.raises(Error) as exc_info:
- request.frame
- assert "Frame for this navigation request is not available" in exc_info.value.message
-
- response = await request.response()
- assert response
- await response.finished()
- await popup_promise
- await clicked
-
-
-async def test_should_parse_the_data_if_content_type_is_application_x_www_form_urlencoded_charset_UTF_8(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- async with page.expect_event("request") as request_info:
- await page.evaluate(
- """() => fetch('./post', {
- method: 'POST',
- headers: {
- 'content-type': 'application/x-www-form-urlencoded; charset=UTF-8',
- },
- body: 'foo=bar&baz=123'
- })"""
- )
- request = await request_info.value
- assert request
- assert request.post_data_json == {"foo": "bar", "baz": "123"}
diff --git a/tests/async/test_page_network_response.py b/tests/async/test_page_network_response.py
deleted file mode 100644
index 76fb7df..0000000
--- a/tests/async/test_page_network_response.py
+++ /dev/null
@@ -1,70 +0,0 @@
-# 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 Error, Page
-from tests.server import Server, TestServerRequest
-
-
-async def test_should_reject_response_finished_if_page_closes(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
-
- def handle_get(request: TestServerRequest) -> None:
- # In Firefox, |fetch| will be hanging until it receives |Content-Type| header
- # from server.
- request.setHeader("Content-Type", "text/plain; charset=utf-8")
- request.write(b"hello ")
-
- server.set_route("/get", handle_get)
- # send request and wait for server response
- [page_response, _] = await asyncio.gather(
- page.wait_for_event("response"),
- page.evaluate("() => fetch('./get', { method: 'GET' })"),
- )
-
- finish_coroutine = page_response.finished()
- await page.close()
- with pytest.raises(Error) as exc_info:
- await finish_coroutine
- error = exc_info.value
- assert "closed" in error.message
-
-
-async def test_should_reject_response_finished_if_context_closes(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
-
- def handle_get(request: TestServerRequest) -> None:
- # In Firefox, |fetch| will be hanging until it receives |Content-Type| header
- # from server.
- request.setHeader("Content-Type", "text/plain; charset=utf-8")
- request.write(b"hello ")
-
- server.set_route("/get", handle_get)
- # send request and wait for server response
- [page_response, _] = await asyncio.gather(
- page.wait_for_event("response"),
- page.evaluate("() => fetch('./get', { method: 'GET' })"),
- )
-
- finish_coroutine = page_response.finished()
- await page.context.close()
- with pytest.raises(Error) as exc_info:
- await finish_coroutine
- error = exc_info.value
- assert "closed" in error.message
diff --git a/tests/async/test_page_request_fallback.py b/tests/async/test_page_request_fallback.py
deleted file mode 100644
index db83628..0000000
--- a/tests/async/test_page_request_fallback.py
+++ /dev/null
@@ -1,352 +0,0 @@
-# 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
-from typing import Any, Callable, Coroutine, cast
-
-import pytest
-
-from playwright.async_api import Error, Page, Request, Route
-from tests.server import Server
-
-
-async def test_should_work(page: Page, server: Server) -> None:
- await page.route("**/*", lambda route: asyncio.create_task(route.fallback()))
- await page.goto(server.EMPTY_PAGE)
-
-
-async def test_should_fall_back(page: Page, server: Server) -> None:
- intercepted = []
-
- def _handler1(route: Route) -> None:
- intercepted.append(1)
- asyncio.create_task(route.fallback())
-
- await page.route("**/empty.html", _handler1)
-
- def _handler2(route: Route) -> None:
- intercepted.append(2)
- asyncio.create_task(route.fallback())
-
- await page.route("**/empty.html", _handler2)
-
- def _handler3(route: Route) -> None:
- intercepted.append(3)
- asyncio.create_task(route.fallback())
-
- await page.route("**/empty.html", _handler3)
-
- await page.goto(server.EMPTY_PAGE)
- assert intercepted == [3, 2, 1]
-
-
-async def test_should_fall_back_async_delayed(page: Page, server: Server) -> None:
- intercepted = []
-
- def create_handler(i: int) -> Callable[[Route], Coroutine]:
- async def handler(route: Route) -> None:
- intercepted.append(i)
- await asyncio.sleep(0.1)
- await route.fallback()
-
- return handler
-
- await page.route("**/empty.html", create_handler(1))
- await page.route("**/empty.html", create_handler(2))
- await page.route("**/empty.html", create_handler(3))
- await page.goto(server.EMPTY_PAGE)
- assert intercepted == [3, 2, 1]
-
-
-async def test_should_chain_once(page: Page, server: Server) -> None:
- await page.route(
- "**/madeup.txt",
- lambda route: asyncio.create_task(route.fulfill(status=200, body="fulfilled one")),
- times=1,
- )
- await page.route("**/madeup.txt", lambda route: asyncio.create_task(route.fallback()), times=1)
-
- resp = await page.goto(server.PREFIX + "/madeup.txt")
- assert resp
- body = await resp.body()
- assert body == b"fulfilled one"
-
-
-async def test_should_not_chain_fulfill(page: Page, server: Server) -> None:
- failed = [False]
-
- def handler(route: Route) -> None:
- failed[0] = True
-
- await page.route("**/empty.html", handler)
- await page.route(
- "**/empty.html",
- lambda route: asyncio.create_task(route.fulfill(status=200, body="fulfilled")),
- )
- await page.route("**/empty.html", lambda route: asyncio.create_task(route.fallback()))
-
- response = await page.goto(server.EMPTY_PAGE)
- assert response
- body = await response.body()
- assert body == b"fulfilled"
- assert not failed[0]
-
-
-async def test_should_not_chain_abort(
- page: Page, server: Server, is_webkit: bool, is_firefox: bool
-) -> None:
- failed = [False]
-
- def handler(route: Route) -> None:
- failed[0] = True
-
- await page.route("**/empty.html", handler)
- await page.route("**/empty.html", lambda route: asyncio.create_task(route.abort()))
- await page.route("**/empty.html", lambda route: asyncio.create_task(route.fallback()))
-
- with pytest.raises(Error) as excinfo:
- await page.goto(server.EMPTY_PAGE)
- if is_webkit:
- assert "Blocked by Web Inspector" in excinfo.value.message
- elif is_firefox:
- assert "NS_ERROR_FAILURE" in excinfo.value.message
- else:
- assert "net::ERR_FAILED" in excinfo.value.message
- assert not failed[0]
-
-
-async def test_should_fall_back_after_exception(page: Page, server: Server) -> None:
- await page.route("**/empty.html", lambda route: route.continue_())
-
- async def handler(route: Route) -> None:
- try:
- await route.fulfill(response=cast(Any, {}))
- except Exception:
- await route.fallback()
-
- await page.route("**/empty.html", handler)
-
- await page.goto(server.EMPTY_PAGE)
-
-
-async def test_should_amend_http_headers(page: Page, server: Server) -> None:
- values = []
-
- async def handler(route: Route) -> None:
- values.append(route.request.headers.get("foo"))
- values.append(await route.request.header_value("FOO"))
- await route.continue_()
-
- await page.route("**/sleep.zzz", handler)
-
- async def handler_with_header_mods(route: Route) -> None:
- await route.fallback(headers={**route.request.headers, "FOO": "bar"})
-
- await page.route("**/*", handler_with_header_mods)
-
- await page.goto(server.EMPTY_PAGE)
- with server.expect_request("/sleep.zzz") as server_request_info:
- await page.evaluate("() => fetch('/sleep.zzz')")
- values.append(server_request_info.value.getHeader("foo"))
- assert values == ["bar", "bar", "bar"]
-
-
-async def test_should_delete_header_with_undefined_value(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- server.set_route(
- "/something",
- lambda r: (
- r.setHeader("Acces-Control-Allow-Origin", "*"),
- r.write(b"done"),
- r.finish(),
- ),
- )
-
- intercepted_request = []
-
- async def capture_and_continue(route: Route, request: Request) -> None:
- intercepted_request.append(request)
- await route.continue_()
-
- await page.route("**/*", capture_and_continue)
-
- async def delete_foo_header(route: Route, request: Request) -> None:
- headers = await request.all_headers()
- del headers["foo"]
- await route.fallback(headers=headers)
-
- await page.route(server.PREFIX + "/something", delete_foo_header)
-
- [server_req, text] = await asyncio.gather(
- server.wait_for_request("/something"),
- page.evaluate(
- """
- async url => {
- const data = await fetch(url, {
- headers: {
- foo: 'a',
- bar: 'b',
- }
- });
- return data.text();
- }
- """,
- server.PREFIX + "/something",
- ),
- )
-
- assert text == "done"
- assert not intercepted_request[0].headers.get("foo")
- assert intercepted_request[0].headers.get("bar") == "b"
- assert not server_req.getHeader("foo")
- assert server_req.getHeader("bar") == "b"
-
-
-async def test_should_amend_method(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
-
- method = []
-
- def _handler(route: Route) -> None:
- method.append(route.request.method)
- asyncio.create_task(route.continue_())
-
- await page.route("**/*", _handler)
- await page.route("**/*", lambda route: asyncio.create_task(route.fallback(method="POST")))
-
- [request, _] = await asyncio.gather(
- server.wait_for_request("/sleep.zzz"),
- page.evaluate("() => fetch('/sleep.zzz')"),
- )
-
- assert method == ["POST"]
- assert request.method == b"POST"
-
-
-async def test_should_override_request_url(page: Page, server: Server) -> None:
- url = []
-
- def _handler1(route: Route) -> None:
- url.append(route.request.url)
- asyncio.create_task(route.continue_())
-
- await page.route("**/global-var.html", _handler1)
-
- def _handler2(route: Route) -> None:
- asyncio.create_task(route.fallback(url=server.PREFIX + "/global-var.html"))
-
- await page.route("**/foo", _handler2)
-
- [server_request, response, _] = await asyncio.gather(
- server.wait_for_request("/global-var.html"),
- page.wait_for_event("response"),
- page.goto(server.PREFIX + "/foo"),
- )
-
- assert url == [server.PREFIX + "/global-var.html"]
- assert response.url == server.PREFIX + "/global-var.html"
- assert response.request.url == server.PREFIX + "/global-var.html"
- assert await page.evaluate("() => window['globalVar']") == 123
- assert server_request.uri == b"/global-var.html"
- assert server_request.method == b"GET"
-
-
-async def test_should_amend_post_data(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- post_data = []
-
- def _handler(route: Route) -> None:
- post_data.append(route.request.post_data)
- asyncio.create_task(route.continue_())
-
- await page.route("**/*", _handler)
- await page.route("**/*", lambda route: asyncio.create_task(route.fallback(post_data="doggo")))
- [server_request, _] = await asyncio.gather(
- server.wait_for_request("/sleep.zzz"),
- page.evaluate("() => fetch('/sleep.zzz', { method: 'POST', body: 'birdy' })"),
- )
- assert post_data == ["doggo"]
- assert server_request.post_body == b"doggo"
-
-
-async def test_should_amend_binary_post_data(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- post_data_buffer = []
-
- def _handler1(route: Route) -> None:
- post_data_buffer.append(route.request.post_data)
- asyncio.create_task(route.continue_())
-
- await page.route("**/*", _handler1)
-
- async def _handler2(route: Route) -> None:
- await route.fallback(post_data=b"\x00\x01\x02\x03\x04")
-
- await page.route("**/*", _handler2)
-
- [server_request, result] = await asyncio.gather(
- server.wait_for_request("/sleep.zzz"),
- page.evaluate("fetch('/sleep.zzz', { method: 'POST', body: 'birdy' })"),
- )
- # FIXME: should this be bytes?
- assert post_data_buffer == ["\x00\x01\x02\x03\x04"]
- assert server_request.method == b"POST"
- assert server_request.post_body == b"\x00\x01\x02\x03\x04"
-
-
-async def test_should_chain_fallback_with_dynamic_url(server: Server, page: Page) -> None:
- intercepted = []
-
- def _handler1(route: Route) -> None:
- intercepted.append(1)
- asyncio.create_task(route.fallback(url=server.EMPTY_PAGE))
-
- await page.route("**/bar", _handler1)
-
- def _handler2(route: Route, request: Request) -> None:
- intercepted.append(2)
- asyncio.create_task(route.fallback(url="http://localhost/bar"))
-
- await page.route("**/foo", _handler2)
-
- def _handler3(route: Route, request: Request) -> None:
- intercepted.append(3)
- asyncio.create_task(route.fallback(url="http://localhost/foo"))
-
- await page.route("**/empty.html", _handler3)
-
- await page.goto(server.EMPTY_PAGE)
- assert intercepted == [3, 2, 1]
-
-
-async def test_should_amend_json_post_data(server: Server, page: Page) -> None:
- await page.goto(server.EMPTY_PAGE)
- post_data = []
-
- def _handle1(route: Route, request: Request) -> None:
- post_data.append(route.request.post_data)
- asyncio.create_task(route.continue_())
-
- await page.route("**/*", _handle1)
- await page.route(
- "**/*",
- lambda route: asyncio.create_task(route.fallback(post_data={"foo": "bar"})),
- )
-
- [server_request, _] = await asyncio.gather(
- server.wait_for_request("/sleep.zzz"),
- page.evaluate("() => fetch('/sleep.zzz', { method: 'POST', body: 'birdy' })"),
- )
- assert post_data == ['{"foo": "bar"}']
- assert server_request.post_body == b'{"foo": "bar"}'
diff --git a/tests/async/test_page_request_intercept.py b/tests/async/test_page_request_intercept.py
deleted file mode 100644
index 1c7b947..0000000
--- a/tests/async/test_page_request_intercept.py
+++ /dev/null
@@ -1,95 +0,0 @@
-# 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
-from typing import cast
-
-import pytest
-
-from playwright.async_api import Error, Page, Route, expect
-from tests.server import Server, TestServerRequest
-
-
-async def test_should_support_timeout_option_in_route_fetch(server: Server, page: Page) -> None:
- def _handler(request: TestServerRequest) -> None:
- request.responseHeaders.addRawHeader("Content-Length", "4096")
- request.responseHeaders.addRawHeader("Content-Type", "text/html")
- request.write(b"")
-
- server.set_route("/slow", _handler)
-
- async def handle(route: Route) -> None:
- with pytest.raises(Error) as error:
- await route.fetch(timeout=1000)
- assert "Request timed out after 1000ms" in error.value.message
-
- await page.route("**/*", lambda route: handle(route))
- with pytest.raises(Error) as error:
- await page.goto(server.PREFIX + "/slow", timeout=2000)
- assert "Timeout 2000ms exceeded" in error.value.message
-
-
-async def test_should_not_follow_redirects_when_max_redirects_is_set_to_0_in_route_fetch(
- server: Server, page: Page
-) -> None:
- server.set_redirect("/foo", "/empty.html")
-
- async def handle(route: Route) -> None:
- response = await route.fetch(max_redirects=0)
- assert response.headers["location"] == "/empty.html"
- assert response.status == 302
- await route.fulfill(body="hello")
-
- await page.route("**/*", lambda route: handle(route))
- await page.goto(server.PREFIX + "/foo")
- assert "hello" in await page.content()
-
-
-async def test_should_intercept_with_url_override(server: Server, page: Page) -> None:
- async def handle(route: Route) -> None:
- response = await route.fetch(url=server.PREFIX + "/one-style.html")
- await route.fulfill(response=response)
-
- await page.route("**/*.html", lambda route: handle(route))
- response = await page.goto(server.PREFIX + "/empty.html")
- assert response
- assert response.status == 200
- assert "one-style.css" in (await response.body()).decode("utf-8")
-
-
-async def test_should_intercept_with_post_data_override(server: Server, page: Page) -> None:
- request_promise = asyncio.create_task(server.wait_for_request("/empty.html"))
-
- async def handle(route: Route) -> None:
- response = await route.fetch(post_data={"foo": "bar"})
- await route.fulfill(response=response)
-
- await page.route("**/*.html", lambda route: handle(route))
- await page.goto(server.PREFIX + "/empty.html")
- request = await request_promise
- assert request.post_body
- assert request.post_body.decode("utf-8") == '{"foo": "bar"}'
-
-
-async def test_should_fulfill_popup_main_request_using_alias(page: Page, server: Server) -> None:
- async def route_handler(route: Route) -> None:
- response = await route.fetch()
- await route.fulfill(response=response, body="hello")
-
- await page.context.route("**/*", route_handler)
- await page.set_content(f'click me ')
- [popup, _] = await asyncio.gather(
- page.wait_for_event("popup"), page.get_by_text("click me").click()
- )
- await expect(cast(Page, popup).locator("body")).to_have_text("hello")
diff --git a/tests/async/test_page_route.py b/tests/async/test_page_route.py
deleted file mode 100644
index 32b1bca..0000000
--- a/tests/async/test_page_route.py
+++ /dev/null
@@ -1,1059 +0,0 @@
-# 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 json
-import re
-from pathlib import Path
-from typing import Callable, List, Optional
-
-import pytest
-
-from playwright._impl._glob import glob_to_regex
-from playwright.async_api import (
- Browser,
- BrowserContext,
- Error,
- Page,
- Playwright,
- Request,
- Route,
-)
-from tests.server import Server, TestServerRequest
-from tests.utils import must
-
-
-async def test_page_route_should_intercept(page: Page, server: Server) -> None:
- intercepted = []
-
- async def handle_request(route: Route, request: Request) -> None:
- assert route.request == request
- assert "empty.html" in request.url
- assert request.headers["user-agent"]
- assert request.method == "GET"
- assert request.post_data is None
- assert request.is_navigation_request()
- assert request.resource_type == "document"
- assert request.frame == page.main_frame
- assert request.frame.url == "about:blank"
- await route.continue_()
- intercepted.append(True)
-
- await page.route("**/empty.html", handle_request)
-
- response = await page.goto(server.EMPTY_PAGE)
- assert response
- assert response.ok
- assert len(intercepted) == 1
-
-
-async def test_page_route_should_unroute(page: Page, server: Server) -> None:
- intercepted = []
-
- def _handle1(route: Route) -> None:
- intercepted.append(1)
- asyncio.create_task(route.continue_())
-
- await page.route("**/*", _handle1)
-
- def _handle2(route: Route, request: Request) -> None:
- intercepted.append(2)
- asyncio.create_task(route.continue_())
-
- await page.route("**/empty.html", _handle2)
-
- def _handle3(route: Route, request: Request) -> None:
- intercepted.append(3)
- asyncio.create_task(route.continue_())
-
- await page.route(
- "**/empty.html",
- _handle3,
- )
-
- def handler4(route: Route) -> None:
- intercepted.append(4)
- asyncio.create_task(route.continue_())
-
- await page.route(re.compile("empty.html"), handler4)
-
- await page.goto(server.EMPTY_PAGE)
- assert intercepted == [4]
-
- intercepted = []
- await page.unroute(re.compile("empty.html"), handler4)
- await page.goto(server.EMPTY_PAGE)
- assert intercepted == [3]
-
- intercepted = []
- await page.unroute("**/empty.html")
- await page.goto(server.EMPTY_PAGE)
- assert intercepted == [1]
-
-
-async def test_page_route_should_work_when_POST_is_redirected_with_302(
- page: Page, server: Server
-) -> None:
- server.set_redirect("/rredirect", "/empty.html")
- await page.goto(server.EMPTY_PAGE)
- await page.route("**/*", lambda route: route.continue_())
- await page.set_content(
- """
-
- """
- )
- async with page.expect_navigation():
- await page.eval_on_selector("form", "form => form.submit()")
-
-
-# @see https://github.com/GoogleChrome/puppeteer/issues/3973
-async def test_page_route_should_work_when_header_manipulation_headers_with_redirect(
- page: Page, server: Server
-) -> None:
- server.set_redirect("/rrredirect", "/empty.html")
- await page.route(
- "**/*",
- lambda route: route.continue_(headers={**route.request.headers, "foo": "bar"}),
- )
-
- await page.goto(server.PREFIX + "/rrredirect")
-
-
-# @see https://github.com/GoogleChrome/puppeteer/issues/4743
-async def test_page_route_should_be_able_to_remove_headers(page: Page, server: Server) -> None:
- async def handle_request(route: Route) -> None:
- headers = route.request.headers
- if "origin" in headers:
- del headers["origin"]
- await route.continue_(headers=headers)
-
- await page.route(
- "**/*", # remove "origin" header
- handle_request,
- )
-
- [serverRequest, _] = await asyncio.gather(
- server.wait_for_request("/empty.html"), page.goto(server.PREFIX + "/empty.html")
- )
- assert serverRequest.getHeader("origin") is None
-
-
-async def test_page_route_should_contain_referer_header(page: Page, server: Server) -> None:
- requests = []
-
- def _handle(route: Route, request: Request) -> None:
- requests.append(route.request)
- asyncio.create_task(route.continue_())
-
- await page.route(
- "**/*",
- _handle,
- )
-
- await page.goto(server.PREFIX + "/one-style.html")
- assert "/one-style.css" in requests[1].url
- assert "/one-style.html" in requests[1].headers["referer"]
-
-
-async def test_page_route_should_properly_return_navigation_response_when_URL_has_cookies(
- context: BrowserContext, page: Page, server: Server
-) -> None:
- # Setup cookie.
- await page.goto(server.EMPTY_PAGE)
- await context.add_cookies([{"url": server.EMPTY_PAGE, "name": "foo", "value": "bar"}])
-
- # Setup request interception.
- await page.route("**/*", lambda route: route.continue_())
- response = await page.reload()
- assert response
- assert response.status == 200
-
-
-async def test_page_route_should_show_custom_HTTP_headers(page: Page, server: Server) -> None:
- await page.set_extra_http_headers({"foo": "bar"})
-
- def assert_headers(request: Request) -> None:
- assert request.headers["foo"] == "bar"
-
- def _handle(route: Route) -> None:
- assert_headers(route.request)
- asyncio.create_task(route.continue_())
-
- await page.route(
- "**/*",
- _handle,
- )
-
- response = await page.goto(server.EMPTY_PAGE)
- assert response
- assert response.ok
-
-
-# @see https://github.com/GoogleChrome/puppeteer/issues/4337
-async def test_page_route_should_work_with_redirect_inside_sync_XHR(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- server.set_redirect("/logo.png", "/pptr.png")
- await page.route("**/*", lambda route: route.continue_())
- status = await page.evaluate(
- """async() => {
- const request = new XMLHttpRequest();
- request.open('GET', '/logo.png', false); // `false` makes the request synchronous
- request.send(null);
- return request.status;
- }"""
- )
-
- assert status == 200
-
-
-async def test_page_route_should_work_with_custom_referer_headers(
- page: Page, server: Server
-) -> None:
- await page.set_extra_http_headers({"referer": server.EMPTY_PAGE})
-
- def assert_headers(route: Route) -> None:
- assert route.request.headers["referer"] == server.EMPTY_PAGE
-
- def _handle(route: Route, request: Request) -> None:
- assert_headers(route)
- asyncio.create_task(route.continue_())
-
- await page.route(
- "**/*",
- _handle,
- )
-
- response = await page.goto(server.EMPTY_PAGE)
- assert response
- assert response.ok
-
-
-async def test_page_route_should_be_abortable(page: Page, server: Server) -> None:
- await page.route(r"/\.css$/", lambda route: asyncio.create_task(route.abort()))
- failed = []
-
- def handle_request(request: Request) -> None:
- if ".css" in request.url:
- failed.append(True)
-
- page.on("requestfailed", handle_request)
-
- response = await page.goto(server.PREFIX + "/one-style.html")
- assert response
- assert response.ok
- assert response.request.failure is None
- assert len(failed) == 0
-
-
-async def test_page_route_should_be_abortable_with_custom_error_codes(
- page: Page, server: Server, is_webkit: bool, is_firefox: bool
-) -> None:
- await page.route(
- "**/*",
- lambda route: route.abort("internetdisconnected"),
- )
- failed_requests = []
- page.on("requestfailed", lambda request: failed_requests.append(request))
- with pytest.raises(Error):
- await page.goto(server.EMPTY_PAGE)
- assert len(failed_requests) == 1
- failed_request = failed_requests[0]
- if is_webkit:
- assert failed_request.failure == "Blocked by Web Inspector"
- elif is_firefox:
- assert failed_request.failure == "NS_ERROR_OFFLINE"
- else:
- assert failed_request.failure == "net::ERR_INTERNET_DISCONNECTED"
-
-
-async def test_page_route_should_send_referer(page: Page, server: Server) -> None:
- await page.set_extra_http_headers({"referer": "http://google.com/"})
-
- await page.route("**/*", lambda route: route.continue_())
- [request, _] = await asyncio.gather(
- server.wait_for_request("/grid.html"),
- page.goto(server.PREFIX + "/grid.html"),
- )
- assert request.getHeader("referer") == "http://google.com/"
-
-
-async def test_page_route_should_fail_navigation_when_aborting_main_resource(
- page: Page, server: Server, is_webkit: bool, is_firefox: bool
-) -> None:
- await page.route("**/*", lambda route: route.abort())
- with pytest.raises(Error) as exc:
- await page.goto(server.EMPTY_PAGE)
- assert exc
- if is_webkit:
- assert "Blocked by Web Inspector" in exc.value.message
- elif is_firefox:
- assert "NS_ERROR_FAILURE" in exc.value.message
- else:
- assert "net::ERR_FAILED" in exc.value.message
-
-
-async def test_page_route_should_not_work_with_redirects(page: Page, server: Server) -> None:
- intercepted = []
-
- def _handle(route: Route, request: Request) -> None:
- asyncio.create_task(route.continue_())
- intercepted.append(route.request)
-
- await page.route(
- "**/*",
- _handle,
- )
-
- server.set_redirect("/non-existing-page.html", "/non-existing-page-2.html")
- server.set_redirect("/non-existing-page-2.html", "/non-existing-page-3.html")
- server.set_redirect("/non-existing-page-3.html", "/non-existing-page-4.html")
- server.set_redirect("/non-existing-page-4.html", "/empty.html")
-
- response = await page.goto(server.PREFIX + "/non-existing-page.html")
- assert response
- assert response.status == 200
- assert "empty.html" in response.url
-
- assert len(intercepted) == 1
- assert intercepted[0].resource_type == "document"
- assert intercepted[0].is_navigation_request()
- assert "/non-existing-page.html" in intercepted[0].url
-
- chain = []
- r: Optional[Request] = response.request
- while r:
- chain.append(r)
- assert r.is_navigation_request()
- r = r.redirected_from
-
- assert len(chain) == 5
- assert "/empty.html" in chain[0].url
- assert "/non-existing-page-4.html" in chain[1].url
- assert "/non-existing-page-3.html" in chain[2].url
- assert "/non-existing-page-2.html" in chain[3].url
- assert "/non-existing-page.html" in chain[4].url
- for idx, _ in enumerate(chain):
- assert chain[idx].redirected_to == (chain[idx - 1] if idx > 0 else None)
-
-
-async def test_page_route_should_work_with_redirects_for_subresources(
- page: Page, server: Server
-) -> None:
- intercepted: List[Request] = []
-
- def _handle(route: Route) -> None:
- asyncio.create_task(route.continue_())
- intercepted.append(route.request)
-
- await page.route(
- "**/*",
- _handle,
- )
-
- server.set_redirect("/one-style.css", "/two-style.css")
- server.set_redirect("/two-style.css", "/three-style.css")
- server.set_redirect("/three-style.css", "/four-style.css")
- server.set_route(
- "/four-style.css",
- lambda req: (req.write(b"body {box-sizing: border-box; }"), req.finish()),
- )
-
- response = await page.goto(server.PREFIX + "/one-style.html")
- assert response
- assert response.status == 200
- assert "one-style.html" in response.url
-
- # 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
-
- r: Optional[Request] = intercepted[1]
- for url in [
- "/one-style.css",
- "/two-style.css",
- "/three-style.css",
- "/four-style.css",
- ]:
- assert r
- assert r.resource_type == "stylesheet"
- assert url in r.url
- r = r.redirected_to
- assert r is None
-
-
-async def test_page_route_should_work_with_equal_requests(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- hits = [True]
-
- def handle_request(request: TestServerRequest, hits: List[bool]) -> None:
- request.write(str(len(hits) * 11).encode())
- request.finish()
- hits.append(True)
-
- server.set_route("/zzz", lambda r: handle_request(r, hits))
-
- spinner: List[bool] = []
-
- async def handle_route(route: Route) -> None:
- if len(spinner) == 1:
- await route.abort()
- spinner.pop(0)
- else:
- await route.continue_()
- spinner.append(True)
-
- # Cancel 2nd request.
- await page.route("**/*", handle_route)
-
- results = []
- for idx in range(3):
- results.append(
- await page.evaluate(
- """() => fetch('/zzz').then(response => response.text()).catch(e => 'FAILED')"""
- )
- )
- assert results == ["11", "FAILED", "22"]
-
-
-async def test_page_route_should_navigate_to_dataURL_and_not_fire_dataURL_requests(
- page: Page, server: Server
-) -> None:
- requests = []
-
- def _handle(route: Route) -> None:
- requests.append(route.request)
- asyncio.create_task(route.continue_())
-
- await page.route(
- "**/*",
- _handle,
- )
-
- data_URL = "data:text/html,yo
"
- response = await page.goto(data_URL)
- assert response is None
- assert len(requests) == 0
-
-
-async def test_page_route_should_be_able_to_fetch_dataURL_and_not_fire_dataURL_requests(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- requests = []
-
- def _handle(route: Route) -> None:
- requests.append(route.request)
- asyncio.create_task(route.continue_())
-
- await page.route("**/*", _handle)
-
- data_URL = "data:text/html,yo
"
- text = await page.evaluate("url => fetch(url).then(r => r.text())", data_URL)
- assert text == "yo
"
- assert len(requests) == 0
-
-
-async def test_page_route_should_navigate_to_URL_with_hash_and_and_fire_requests_without_hash(
- page: Page, server: Server
-) -> None:
- requests = []
-
- def _handle(route: Route) -> None:
- requests.append(route.request)
- asyncio.create_task(route.continue_())
-
- await page.route(
- "**/*",
- _handle,
- )
-
- response = await page.goto(server.EMPTY_PAGE + "#hash")
- assert response
- assert response.status == 200
- assert response.url == server.EMPTY_PAGE
- assert len(requests) == 1
- assert requests[0].url == server.EMPTY_PAGE
-
-
-async def test_page_route_should_work_with_encoded_server(page: Page, server: Server) -> None:
- # The requestWillBeSent will report encoded URL, whereas interception will
- # report URL as-is. @see crbug.com/759388
- await page.route("**/*", lambda route: route.continue_())
- response = await page.goto(server.PREFIX + "/some nonexisting page")
- assert response
- assert response.status == 404
-
-
-async def test_page_route_should_work_with_encoded_server___2(page: Page, server: Server) -> None:
- # The requestWillBeSent will report URL as-is, whereas interception will
- # report encoded URL for stylesheet. @see crbug.com/759388
- requests: List[Request] = []
-
- def _handle(route: Route) -> None:
- asyncio.create_task(route.continue_())
- requests.append(route.request)
-
- await page.route("**/*", _handle)
-
- response = await page.goto(
- f"""data:text/html, """
- )
- assert response is None
- # TODO: https://github.com/microsoft/playwright/issues/12789
- assert len(requests) >= 1
- assert (must(await requests[0].response())).status == 404
-
-
-async def test_page_route_should_not_throw_Invalid_Interception_Id_if_the_request_was_cancelled(
- page: Page, server: Server
-) -> None:
- await page.set_content("")
- route_future: "asyncio.Future[Route]" = asyncio.Future()
- await page.route("**/*", lambda r, _: route_future.set_result(r))
-
- async with page.expect_request("**/*"):
- await page.eval_on_selector(
- "iframe", """(frame, url) => frame.src = url""", server.EMPTY_PAGE
- )
- # Delete frame to cause request to be canceled.
- await page.eval_on_selector("iframe", "frame => frame.remove()")
- route = await route_future
- await route.continue_()
-
-
-async def test_page_route_should_intercept_main_resource_during_cross_process_navigation(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- intercepted = []
-
- def _handle(route: Route) -> None:
- intercepted.append(True)
- asyncio.create_task(route.continue_())
-
- await page.route(
- server.CROSS_PROCESS_PREFIX + "/empty.html",
- _handle,
- )
-
- response = await page.goto(server.CROSS_PROCESS_PREFIX + "/empty.html")
- assert response
- assert response.ok
- assert len(intercepted) == 1
-
-
-@pytest.mark.skip_browser("webkit")
-async def test_page_route_should_create_a_redirect(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/empty.html")
-
- async def handle_route(route: Route, request: Request) -> None:
- if request.url != (server.PREFIX + "/redirect_this"):
- return await route.continue_()
- await route.fulfill(status=301, headers={"location": "/empty.html"})
-
- await page.route(
- "**/*",
- handle_route,
- )
-
- text = await page.evaluate(
- """async url => {
- const data = await fetch(url);
- return data.text();
- }""",
- server.PREFIX + "/redirect_this",
- )
- assert text == ""
-
-
-async def test_page_route_should_support_cors_with_GET(
- page: Page, server: Server, browser_name: str
-) -> None:
- await page.goto(server.EMPTY_PAGE)
-
- async def handle_route(route: Route, request: Request) -> None:
- headers = {"access-control-allow-origin": "*" if request.url.endswith("allow") else "none"}
- await route.fulfill(
- content_type="application/json",
- headers=headers,
- status=200,
- body=json.dumps(["electric", "gas"]),
- )
-
- await page.route(
- "**/cars*",
- handle_route,
- )
- # Should succeed
- resp = await page.evaluate(
- """async () => {
- const response = await fetch('https://example.com/cars?allow', { mode: 'cors' });
- return response.json();
- }"""
- )
-
- assert resp == ["electric", "gas"]
-
- # Should be rejected
- with pytest.raises(Error) as exc:
- await page.evaluate(
- """async () => {
- const response = await fetch('https://example.com/cars?reject', { mode: 'cors' });
- return response.json();
- }"""
- )
- if browser_name == "chromium":
- assert "Failed" in exc.value.message
- elif browser_name == "webkit":
- assert "TypeError" in exc.value.message
- elif browser_name == "firefox":
- assert "NetworkError" in exc.value.message
-
-
-async def test_page_route_should_support_cors_with_POST(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- await page.route(
- "**/cars",
- lambda route: route.fulfill(
- content_type="application/json",
- headers={"Access-Control-Allow-Origin": "*"},
- status=200,
- body=json.dumps(["electric", "gas"]),
- ),
- )
-
- resp = await page.evaluate(
- """async () => {
- const response = await fetch('https://example.com/cars', {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- mode: 'cors',
- body: JSON.stringify({ 'number': 1 })
- });
- return response.json();
- }"""
- )
-
- assert resp == ["electric", "gas"]
-
-
-async def test_page_route_should_support_cors_for_different_methods(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- await page.route(
- "**/cars",
- lambda route, request: route.fulfill(
- content_type="application/json",
- headers={"Access-Control-Allow-Origin": "*"},
- status=200,
- body=json.dumps([request.method, "electric", "gas"]),
- ),
- )
-
- # First POST
- resp = await page.evaluate(
- """async () => {
- const response = await fetch('https://example.com/cars', {
- method: 'POST',
- headers: { 'Content-Type': 'application/json' },
- mode: 'cors',
- body: JSON.stringify({ 'number': 1 })
- });
- return response.json();
- }"""
- )
-
- assert resp == ["POST", "electric", "gas"]
- # Then DELETE
- resp = await page.evaluate(
- """async () => {
- const response = await fetch('https://example.com/cars', {
- method: 'DELETE',
- headers: {},
- mode: 'cors',
- body: ''
- });
- return response.json();
- }"""
- )
-
- assert resp == ["DELETE", "electric", "gas"]
-
-
-async def test_request_fulfill_should_work_a(page: Page, server: Server) -> None:
- await page.route(
- "**/*",
- lambda route: route.fulfill(
- status=201,
- headers={"foo": "bar"},
- content_type="text/html",
- body="Yo, page!",
- ),
- )
-
- response = await page.goto(server.EMPTY_PAGE)
- assert response
- assert response.status == 201
- assert response.headers["foo"] == "bar"
- assert await page.evaluate("() => document.body.textContent") == "Yo, page!"
-
-
-async def test_request_fulfill_should_work_with_status_code_422(page: Page, server: Server) -> None:
- await page.route(
- "**/*",
- lambda route: route.fulfill(status=422, body="Yo, page!"),
- )
-
- response = await page.goto(server.EMPTY_PAGE)
- assert response
- assert response.status == 422
- assert response.status_text == "Unprocessable Entity"
- assert await page.evaluate("() => document.body.textContent") == "Yo, page!"
-
-
-async def test_request_fulfill_should_allow_mocking_binary_responses(
- page: Page,
- server: Server,
- assert_to_be_golden: Callable[[bytes, str], None],
- assetdir: Path,
-) -> None:
- await page.route(
- "**/*",
- lambda route: route.fulfill(
- content_type="image/png",
- body=(assetdir / "pptr.png").read_bytes(),
- ),
- )
-
- await page.evaluate(
- """PREFIX => {
- const img = document.createElement('img');
- img.src = PREFIX + '/does-not-exist.png';
- document.body.appendChild(img);
- return new Promise(fulfill => img.onload = fulfill);
- }""",
- server.PREFIX,
- )
- img = await page.query_selector("img")
- assert img
- assert_to_be_golden(await img.screenshot(), "mock-binary-response.png")
-
-
-async def test_request_fulfill_should_allow_mocking_svg_with_charset(
- page: Page, server: Server, assert_to_be_golden: Callable[[bytes, str], None]
-) -> None:
- await page.route(
- "**/*",
- lambda route: route.fulfill(
- content_type="image/svg+xml ; charset=utf-8",
- body=' ',
- ),
- )
-
- await page.evaluate(
- """PREFIX => {
- const img = document.createElement('img');
- img.src = PREFIX + '/does-not-exist.svg';
- document.body.appendChild(img);
- return new Promise((f, r) => { img.onload = f; img.onerror = r; });
- }""",
- server.PREFIX,
- )
- img = await page.query_selector("img")
- assert img
- assert_to_be_golden(await img.screenshot(), "mock-svg.png")
-
-
-async def test_request_fulfill_should_work_with_file_path(
- page: Page,
- server: Server,
- assert_to_be_golden: Callable[[bytes, str], None],
- assetdir: Path,
-) -> None:
- await page.route(
- "**/*",
- lambda route: route.fulfill(content_type="shouldBeIgnored", path=assetdir / "pptr.png"),
- )
- await page.evaluate(
- """PREFIX => {
- const img = document.createElement('img');
- img.src = PREFIX + '/does-not-exist.png';
- document.body.appendChild(img);
- return new Promise(fulfill => img.onload = fulfill);
- }""",
- server.PREFIX,
- )
- img = await page.query_selector("img")
- assert img
- assert_to_be_golden(await img.screenshot(), "mock-binary-response.png")
-
-
-async def test_request_fulfill_should_stringify_intercepted_request_response_headers(
- page: Page, server: Server
-) -> None:
- await page.route(
- "**/*",
- lambda route: route.fulfill(
- status=200, headers={"foo": True}, body="Yo, page!" # type: ignore
- ),
- )
-
- response = await page.goto(server.EMPTY_PAGE)
- assert response
- assert response.status == 200
- headers = response.headers
- assert headers["foo"] == "True"
- assert await page.evaluate("() => document.body.textContent") == "Yo, page!"
-
-
-async def test_request_fulfill_should_not_modify_the_headers_sent_to_the_server(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/empty.html")
- interceptedRequests = []
-
- # this is just to enable request interception, which disables caching in chromium
- await page.route(server.PREFIX + "/unused", lambda route, req: None)
-
- def _handler1(response: TestServerRequest) -> None:
- interceptedRequests.append(response)
- response.setHeader("Access-Control-Allow-Origin", "*")
- response.write(b"done")
- response.finish()
-
- server.set_route("/something", _handler1)
-
- text = await page.evaluate(
- """async url => {
- const data = await fetch(url);
- return data.text();
- }""",
- server.CROSS_PROCESS_PREFIX + "/something",
- )
- assert text == "done"
-
- playwrightRequest: "asyncio.Future[Request]" = asyncio.Future()
-
- def _handler2(route: Route, request: Request) -> None:
- playwrightRequest.set_result(request)
- asyncio.create_task(route.continue_(headers={**request.headers}))
-
- await page.route(
- server.CROSS_PROCESS_PREFIX + "/something",
- _handler2,
- )
-
- textAfterRoute = await page.evaluate(
- """async url => {
- const data = await fetch(url);
- return data.text();
- }""",
- server.CROSS_PROCESS_PREFIX + "/something",
- )
- assert textAfterRoute == "done"
-
- assert len(interceptedRequests) == 2
- assert interceptedRequests[0].requestHeaders == interceptedRequests[1].requestHeaders
-
-
-async def test_request_fulfill_should_include_the_origin_header(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/empty.html")
- interceptedRequest = []
-
- def _handle(route: Route, request: Request) -> None:
- interceptedRequest.append(request)
- asyncio.create_task(
- route.fulfill(
- headers={"Access-Control-Allow-Origin": "*"},
- content_type="text/plain",
- body="done",
- )
- )
-
- await page.route(server.CROSS_PROCESS_PREFIX + "/something", _handle)
-
- text = await page.evaluate(
- """async url => {
- const data = await fetch(url);
- return data.text();
- }""",
- server.CROSS_PROCESS_PREFIX + "/something",
- )
- assert text == "done"
- assert len(interceptedRequest) == 1
- assert interceptedRequest[0].headers["origin"] == server.PREFIX
-
-
-async def test_request_fulfill_should_work_with_request_interception(
- page: Page, server: Server
-) -> None:
- requests = {}
-
- async def _handle_route(route: Route) -> None:
- requests[route.request.url.split("/").pop()] = route.request
- await route.continue_()
-
- await page.route("**/*", _handle_route)
-
- server.set_redirect("/rrredirect", "/frames/one-frame.html")
- await page.goto(server.PREFIX + "/rrredirect")
- assert requests["rrredirect"].is_navigation_request()
- assert requests["frame.html"].is_navigation_request()
- assert requests["script.js"].is_navigation_request() is False
- assert requests["style.css"].is_navigation_request() is False
-
-
-async def test_Interception_should_work_with_request_interception(
- browser: Browser, https_server: Server
-) -> None:
- context = await browser.new_context(ignore_https_errors=True)
- page = await context.new_page()
-
- await page.route("**/*", lambda route: asyncio.ensure_future(route.continue_()))
- response = await page.goto(https_server.EMPTY_PAGE)
- assert response
- assert response.status == 200
- await context.close()
-
-
-async def test_ignore_http_errors_service_worker_should_intercept_after_a_service_worker(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/serviceworkers/fetchdummy/sw.html")
- await page.evaluate("() => window.activationPromise")
-
- # Sanity check.
- sw_response = await page.evaluate('() => fetchDummy("foo")')
- assert sw_response == "responseFromServiceWorker:foo"
-
- def _handle_route(route: Route) -> None:
- asyncio.ensure_future(
- route.fulfill(
- status=200,
- content_type="text/css",
- body="responseFromInterception:" + route.request.url.split("/")[-1],
- )
- )
-
- await page.route("**/foo", _handle_route)
-
- # Page route is applied after service worker fetch event.
- sw_response2 = await page.evaluate('() => fetchDummy("foo")')
- assert sw_response2 == "responseFromServiceWorker:foo"
-
- # Page route is not applied to service worker initiated fetch.
- non_intercepted_response = await page.evaluate('() => fetchDummy("passthrough")')
- assert non_intercepted_response == "FAILURE: Not Found"
-
-
-async def test_page_route_should_support_times_parameter(page: Page, server: Server) -> None:
- intercepted = []
-
- async def handle_request(route: Route) -> None:
- await route.continue_()
- intercepted.append(True)
-
- await page.route("**/empty.html", handle_request, times=1)
-
- await page.goto(server.EMPTY_PAGE)
- await page.goto(server.EMPTY_PAGE)
- await page.goto(server.EMPTY_PAGE)
- assert len(intercepted) == 1
-
-
-async def test_should_work_if_handler_with_times_parameter_was_removed_from_another_handler(
- context: BrowserContext, page: Page, server: Server
-) -> None:
- intercepted = []
-
- async def handler(route: Route) -> None:
- intercepted.append("first")
- await route.continue_()
-
- await page.route("**/*", handler, times=1)
-
- async def handler2(route: Route) -> None:
- intercepted.append("second")
- await page.unroute("**/*", handler)
- await route.fallback()
-
- await page.route("**/*", handler2)
- await page.goto(server.EMPTY_PAGE)
- assert intercepted == ["second"]
- intercepted.clear()
- await page.goto(server.EMPTY_PAGE)
- assert intercepted == ["second"]
-
-
-async def test_should_fulfill_with_global_fetch_result(
- page: Page, playwright: Playwright, server: Server
-) -> None:
- async def handle_request(route: Route) -> None:
- request = await playwright.request.new_context()
- response = await request.get(server.PREFIX + "/simple.json")
- await route.fulfill(response=response)
- await request.dispose()
-
- await page.route("**/*", handle_request)
-
- response = await page.goto(server.EMPTY_PAGE)
- assert response
- assert response.status == 200
- assert await response.json() == {"foo": "bar"}
-
-
-async def test_glob_to_regex() -> None:
- assert glob_to_regex("**/*.js").match("https://localhost:8080/foo.js")
- assert not glob_to_regex("**/*.css").match("https://localhost:8080/foo.js")
- assert not glob_to_regex("*.js").match("https://localhost:8080/foo.js")
- assert glob_to_regex("https://**/*.js").match("https://localhost:8080/foo.js")
- assert glob_to_regex("http://localhost:8080/simple/path.js").match(
- "http://localhost:8080/simple/path.js"
- )
- assert glob_to_regex("http://localhost:8080/?imple/path.js").match(
- "http://localhost:8080/Simple/path.js"
- )
- assert glob_to_regex("**/{a,b}.js").match("https://localhost:8080/a.js")
- assert glob_to_regex("**/{a,b}.js").match("https://localhost:8080/b.js")
- assert not glob_to_regex("**/{a,b}.js").match("https://localhost:8080/c.js")
-
- assert glob_to_regex("**/*.{png,jpg,jpeg}").match("https://localhost:8080/c.jpg")
- assert glob_to_regex("**/*.{png,jpg,jpeg}").match("https://localhost:8080/c.jpeg")
- assert glob_to_regex("**/*.{png,jpg,jpeg}").match("https://localhost:8080/c.png")
- assert not glob_to_regex("**/*.{png,jpg,jpeg}").match("https://localhost:8080/c.css")
- assert glob_to_regex("foo*").match("foo.js")
- assert not glob_to_regex("foo*").match("foo/bar.js")
- assert not glob_to_regex("http://localhost:3000/signin-oidc*").match(
- "http://localhost:3000/signin-oidc/foo"
- )
- assert glob_to_regex("http://localhost:3000/signin-oidc*").match(
- "http://localhost:3000/signin-oidcnice"
- )
-
- assert glob_to_regex("**/three-columns/settings.html?**id=[a-z]**").match(
- "http://mydomain:8080/blah/blah/three-columns/settings.html?id=settings-e3c58efe-02e9-44b0-97ac-dd138100cf7c&blah"
- )
-
- assert glob_to_regex("\\?") == re.compile(r"^\?$")
- assert glob_to_regex("\\") == re.compile(r"^\\$")
- assert glob_to_regex("\\\\") == re.compile(r"^\\$")
- assert glob_to_regex("\\[") == re.compile(r"^\[$")
- assert glob_to_regex("[a-z]") == re.compile(r"^[a-z]$")
- assert glob_to_regex("$^+.\\*()|\\?\\{\\}\\[\\]") == re.compile(r"^\$\^\+\.\*\(\)\|\?\{\}\[\]$")
diff --git a/tests/async/test_page_select_option.py b/tests/async/test_page_select_option.py
deleted file mode 100644
index 370a9db..0000000
--- a/tests/async/test_page_select_option.py
+++ /dev/null
@@ -1,214 +0,0 @@
-# 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 pytest
-
-from playwright.async_api import Error, Page, TimeoutError
-from tests.server import Server
-
-
-async def test_select_option_should_select_single_option(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/select.html")
- await page.select_option("select", "blue")
- assert await page.evaluate("result.onInput") == ["blue"]
- assert await page.evaluate("result.onChange") == ["blue"]
-
-
-async def test_select_option_should_select_single_option_by_value(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/input/select.html")
- await page.select_option("select", "blue")
- assert await page.evaluate("result.onInput") == ["blue"]
- assert await page.evaluate("result.onChange") == ["blue"]
-
-
-async def test_select_option_should_select_single_option_by_label(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/input/select.html")
- await page.select_option("select", label="Indigo")
- assert await page.evaluate("result.onInput") == ["indigo"]
- assert await page.evaluate("result.onChange") == ["indigo"]
-
-
-async def test_select_option_should_select_single_option_by_handle(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/input/select.html")
- await page.select_option("select", element=await page.query_selector("[id=whiteOption]"))
- assert await page.evaluate("result.onInput") == ["white"]
- assert await page.evaluate("result.onChange") == ["white"]
-
-
-async def test_select_option_should_select_single_option_by_index(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/input/select.html")
- await page.select_option("select", index=2)
- assert await page.evaluate("result.onInput") == ["brown"]
- assert await page.evaluate("result.onChange") == ["brown"]
-
-
-async def test_select_option_should_select_only_first_option(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/select.html")
- await page.select_option("select", ["blue", "green", "red"])
- assert await page.evaluate("result.onInput") == ["blue"]
- assert await page.evaluate("result.onChange") == ["blue"]
-
-
-async def test_select_option_should_not_throw_when_select_causes_navigation(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/input/select.html")
- await page.eval_on_selector(
- "select",
- "select => select.addEventListener('input', () => window.location = '/empty.html')",
- )
- async with page.expect_navigation():
- await page.select_option("select", "blue")
- assert "empty.html" in page.url
-
-
-async def test_select_option_should_select_multiple_options(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/select.html")
- await page.evaluate("makeMultiple()")
- await page.select_option("select", ["blue", "green", "red"])
- assert await page.evaluate("result.onInput") == ["blue", "green", "red"]
- assert await page.evaluate("result.onChange") == ["blue", "green", "red"]
-
-
-async def test_select_option_should_select_multiple_options_with_attributes(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/input/select.html")
- await page.evaluate("makeMultiple()")
- await page.select_option(
- "select",
- value="blue",
- label="Green",
- index=4,
- )
- assert await page.evaluate("result.onInput") == ["blue", "gray", "green"]
- assert await page.evaluate("result.onChange") == ["blue", "gray", "green"]
-
-
-async def test_select_option_should_respect_event_bubbling(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/select.html")
- await page.select_option("select", "blue")
- assert await page.evaluate("result.onBubblingInput") == ["blue"]
- assert await page.evaluate("result.onBubblingChange") == ["blue"]
-
-
-async def test_select_option_should_throw_when_element_is_not_a__select_(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/input/select.html")
- with pytest.raises(Error) as exc_info:
- await page.select_option("body", "")
- assert "Element is not a element" in exc_info.value.message
-
-
-async def test_select_option_should_return_on_no_matched_values(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/select.html")
- with pytest.raises(TimeoutError) as exc_info:
- await page.select_option("select", ["42", "abc"], timeout=1000)
- assert "Timeout 1000" in exc_info.value.message
-
-
-async def test_select_option_should_return_an_array_of_matched_values(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/input/select.html")
- await page.evaluate("makeMultiple()")
- result = await page.select_option("select", ["blue", "black", "magenta"])
- assert result == ["black", "blue", "magenta"]
-
-
-async def test_select_option_should_return_an_array_of_one_element_when_multiple_is_not_set(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/input/select.html")
- result = await page.select_option("select", ["42", "blue", "black", "magenta"])
- assert len(result) == 1
-
-
-async def test_select_option_should_return_on_no_values(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/select.html")
- result = await page.select_option("select", [])
- assert result == []
-
-
-async def test_select_option_should_not_allow_null_items(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/select.html")
- await page.evaluate("makeMultiple()")
- with pytest.raises(Error) as exc_info:
- await page.select_option("select", ["blue", None, "black", "magenta"]) # type: ignore
- assert "expected string, got object" in exc_info.value.message
-
-
-async def test_select_option_should_unselect_with_null(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/input/select.html")
- await page.evaluate("makeMultiple()")
- result = await page.select_option("select", ["blue", "black", "magenta"])
- assert result == ["black", "blue", "magenta"]
- await page.select_option("select", None)
- assert await page.eval_on_selector(
- "select",
- "select => Array.from(select.options).every(option => !option.selected)",
- )
-
-
-async def test_select_option_should_deselect_all_options_when_passed_no_values_for_a_multiple_select(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/input/select.html")
- await page.evaluate("makeMultiple()")
- await page.select_option("select", ["blue", "black", "magenta"])
- await page.select_option("select", [])
- assert await page.eval_on_selector(
- "select",
- "select => Array.from(select.options).every(option => !option.selected)",
- )
-
-
-async def test_select_option_should_deselect_all_options_when_passed_no_values_for_a_select_without_multiple(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/input/select.html")
- await page.select_option("select", ["blue", "black", "magenta"])
- await page.select_option("select", [])
- assert await page.eval_on_selector(
- "select",
- "select => Array.from(select.options).every(option => !option.selected)",
- )
-
-
-async def test_select_option_should_work_when_re_defining_top_level_event_class(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/input/select.html")
- await page.evaluate("window.Event = null")
- await page.select_option("select", "blue")
- assert await page.evaluate("result.onInput") == ["blue"]
- assert await page.evaluate("result.onChange") == ["blue"]
-
-
-async def test_select_options_should_fall_back_to_selecting_by_label(
- page: Page, server: Server
-) -> None:
- await page.goto(server.PREFIX + "/input/select.html")
- await page.select_option("select", "Blue")
- assert await page.evaluate("result.onInput") == ["blue"]
- assert await page.evaluate("result.onChange") == ["blue"]
diff --git a/tests/async/test_pdf.py b/tests/async/test_pdf.py
deleted file mode 100644
index 876cd34..0000000
--- a/tests/async/test_pdf.py
+++ /dev/null
@@ -1,43 +0,0 @@
-# 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.async_api import Page
-from tests.server import Server
-
-pytestmark = pytest.mark.only_browser("chromium")
-
-
-async def test_should_be_able_to_save_pdf_file(page: Page, tmpdir: Path) -> None:
- output_file = tmpdir / "foo.png"
- await page.pdf(path=str(output_file))
- assert os.path.getsize(output_file) > 0
-
-
-async def test_should_be_able_capture_pdf_without_path(page: Page) -> None:
- buffer = await page.pdf()
- assert buffer
-
-
-async def test_should_be_able_to_generate_outline(page: Page, server: Server, tmpdir: Path) -> None:
- await page.goto(server.PREFIX + "/headings.html")
- output_file_no_outline = tmpdir / "outputNoOutline.pdf"
- output_file_outline = tmpdir / "outputOutline.pdf"
- await page.pdf(path=output_file_no_outline)
- await page.pdf(path=output_file_outline, tagged=True, outline=True)
- assert os.path.getsize(output_file_outline) > os.path.getsize(output_file_no_outline)
diff --git a/tests/async/test_popup.py.disabled b/tests/async/test_popup.py.disabled
deleted file mode 100644
index c153f16..0000000
--- a/tests/async/test_popup.py.disabled
+++ /dev/null
@@ -1,448 +0,0 @@
-# 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
-from typing import List, Optional
-
-from playwright.async_api import Browser, BrowserContext, Request, Route
-
-from tests.server import Server
-from tests.utils import must
-
-
-async def test_link_navigation_inherit_user_agent_from_browser_context(
- browser: Browser, server: Server
-) -> None:
- context = await browser.new_context(user_agent="hey")
-
- page = await context.new_page()
- await page.goto(server.EMPTY_PAGE)
- await page.set_content('link ')
- request_waitable = asyncio.create_task(server.wait_for_request("/popup/popup.html"))
- await asyncio.sleep(0) # execute scheduled tasks, but don't await them
- async with context.expect_page() as page_info:
- await page.click("a")
- popup = await page_info.value
- await popup.wait_for_load_state("domcontentloaded")
- user_agent = await popup.evaluate("window.initialUserAgent")
- request = await request_waitable
- assert user_agent == "hey"
- assert request.requestHeaders.getRawHeaders("user-agent") == ["hey"]
- await context.close()
-
-
-async def test_link_navigation_respect_routes_from_browser_context(
- context: BrowserContext, server: Server
-) -> None:
- page = await context.new_page()
- await page.goto(server.EMPTY_PAGE)
- await page.set_content('link ')
-
- intercepted: List[bool] = []
-
- async def handle_request(route: Route) -> None:
- intercepted.append(True)
- await route.continue_()
-
- await context.route("**/empty.html", handle_request)
- async with context.expect_page():
- await page.click("a")
- assert intercepted == [True]
-
-
-async def test_window_open_inherit_user_agent_from_browser_context(
- browser: Browser, server: Server
-) -> None:
- context = await browser.new_context(user_agent="hey")
-
- page = await context.new_page()
- await page.goto(server.EMPTY_PAGE)
- request_promise = asyncio.create_task(server.wait_for_request("/dummy.html"))
- await asyncio.sleep(0) # execute scheduled tasks, but don't await them
- user_agent = await page.evaluate(
- """url => {
- win = window.open(url)
- return win.navigator.userAgent
- }""",
- server.PREFIX + "/dummy.html",
- )
- request = await request_promise
- assert user_agent == "hey"
- assert request.requestHeaders.getRawHeaders("user-agent") == ["hey"]
- await context.close()
-
-
-async def test_should_inherit_extra_headers_from_browser_context(
- browser: Browser, server: Server
-) -> None:
- context = await browser.new_context(extra_http_headers={"foo": "bar"})
-
- page = await context.new_page()
- await page.goto(server.EMPTY_PAGE)
- request_promise = asyncio.create_task(server.wait_for_request("/dummy.html"))
- await asyncio.sleep(0) # execute scheduled tasks, but don't await them
- await page.evaluate("url => window._popup = window.open(url)", server.PREFIX + "/dummy.html")
- request = await request_promise
- assert request.requestHeaders.getRawHeaders("foo") == ["bar"]
- await context.close()
-
-
-async def test_should_inherit_offline_from_browser_context(
- context: BrowserContext, server: Server
-) -> None:
- page = await context.new_page()
- await page.goto(server.EMPTY_PAGE)
- await context.set_offline(True)
- online = await page.evaluate(
- """url => {
- win = window.open(url)
- return win.navigator.onLine
- }""",
- server.PREFIX + "/dummy.html",
- )
- assert online is False
-
-
-async def test_should_inherit_http_credentials_from_browser_context(
- browser: Browser, server: Server
-) -> None:
- server.set_auth("/title.html", "user", "pass")
- context = await browser.new_context(http_credentials={"username": "user", "password": "pass"})
- page = await context.new_page()
- await page.goto(server.EMPTY_PAGE)
- async with page.expect_popup() as popup_info:
- await page.evaluate(
- "url => window._popup = window.open(url)", server.PREFIX + "/title.html"
- )
- popup = await popup_info.value
- await popup.wait_for_load_state("domcontentloaded")
- assert await popup.title() == "Woof-Woof"
- await context.close()
-
-
-async def test_should_inherit_touch_support_from_browser_context(
- browser: Browser, server: Server
-) -> None:
- context = await browser.new_context(viewport={"width": 400, "height": 500}, has_touch=True)
-
- page = await context.new_page()
- await page.goto(server.EMPTY_PAGE)
- has_touch = await page.evaluate(
- """() => {
- win = window.open('')
- return 'ontouchstart' in win
- }"""
- )
-
- assert has_touch
- await context.close()
-
-
-async def test_should_inherit_viewport_size_from_browser_context(
- browser: Browser, server: Server
-) -> None:
- context = await browser.new_context(viewport={"width": 400, "height": 500})
-
- page = await context.new_page()
- await page.goto(server.EMPTY_PAGE)
- size = await page.evaluate(
- """() => {
- win = window.open('about:blank')
- return { width: win.innerWidth, height: win.innerHeight }
- }"""
- )
-
- assert size == {"width": 400, "height": 500}
- await context.close()
-
-
-@pytest.mark.skip(reason="Not supported by Camoufox")
-async def test_should_use_viewport_size_from_window_features(
- browser: Browser, server: Server
-) -> None:
- context = await browser.new_context(viewport={"width": 700, "height": 700})
- page = await context.new_page()
- await page.goto(server.EMPTY_PAGE)
- size = None
- async with page.expect_popup() as popup_info:
- size = await page.evaluate(
- """async () => {
- const win = window.open(window.location.href, 'Title', 'toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=600,height=300,top=0,left=0');
- await new Promise(resolve => {
- const interval = setInterval(() => {
- if (win.innerWidth === 600 && win.innerHeight === 300) {
- clearInterval(interval);
- resolve();
- }
- }, 10);
- });
- return { width: win.innerWidth, height: win.innerHeight }
- }"""
- )
- popup = await popup_info.value
- await popup.set_viewport_size({"width": 500, "height": 400})
- await popup.wait_for_load_state()
- resized = await popup.evaluate(
- "() => ({ width: window.innerWidth, height: window.innerHeight })"
- )
- await context.close()
- assert size == {"width": 600, "height": 300}
- assert resized == {"width": 500, "height": 400}
-
-
-async def test_should_respect_routes_from_browser_context(
- context: BrowserContext, server: Server
-) -> None:
- page = await context.new_page()
- await page.goto(server.EMPTY_PAGE)
-
- def handle_request(route: Route, request: Request, intercepted: List[bool]) -> None:
- asyncio.create_task(route.continue_())
- intercepted.append(True)
-
- intercepted: List[bool] = []
- await context.route(
- "**/empty.html",
- lambda route, request: handle_request(route, request, intercepted),
- )
-
- async with page.expect_popup():
- await page.evaluate("url => window.__popup = window.open(url)", server.EMPTY_PAGE)
- assert len(intercepted) == 1
-
-
-async def test_browser_context_add_init_script_should_apply_to_an_in_process_popup(
- context: BrowserContext, server: Server
-) -> None:
- await context.add_init_script("window.injected = 123")
- page = await context.new_page()
- await page.goto(server.EMPTY_PAGE)
- injected = await page.evaluate(
- """() => {
- const win = window.open('about:blank');
- return win.injected;
- }"""
- )
-
- assert injected == 123
-
-
-async def test_browser_context_add_init_script_should_apply_to_a_cross_process_popup(
- context: BrowserContext, server: Server
-) -> None:
- await context.add_init_script("window.injected = 123")
- page = await context.new_page()
- await page.goto(server.EMPTY_PAGE)
- async with page.expect_popup() as popup_info:
- await page.evaluate("url => window.open(url)", server.CROSS_PROCESS_PREFIX + "/title.html")
- popup = await popup_info.value
- assert await popup.evaluate("injected") == 123
- await popup.reload()
- assert await popup.evaluate("injected") == 123
-
-
-async def test_should_expose_function_from_browser_context(
- context: BrowserContext, server: Server
-) -> None:
- await context.expose_function("add", lambda a, b: a + b)
- page = await context.new_page()
- await page.goto(server.EMPTY_PAGE)
- added = await page.evaluate(
- """async () => {
- win = window.open('about:blank')
- return win.add(9, 4)
- }"""
- )
-
- assert added == 13
-
-
-async def test_should_work(context: BrowserContext) -> None:
- page = await context.new_page()
- async with page.expect_popup() as popup_info:
- await page.evaluate('window.__popup = window.open("about:blank")')
- popup = await popup_info.value
- assert await page.evaluate("!!window.opener") is False
- assert await popup.evaluate("!!window.opener")
-
-
-async def test_should_work_with_window_features(context: BrowserContext, server: Server) -> None:
- page = await context.new_page()
- await page.goto(server.EMPTY_PAGE)
- async with page.expect_popup() as popup_info:
- await page.evaluate(
- 'window.__popup = window.open(window.location.href, "Title", "toolbar=no,location=no,directories=no,status=no,menubar=no,scrollbars=yes,resizable=yes,width=780,height=200,top=0,left=0")'
- )
- popup = await popup_info.value
- assert await page.evaluate("!!window.opener") is False
- assert await popup.evaluate("!!window.opener")
-
-
-async def test_window_open_emit_for_immediately_closed_popups(
- context: BrowserContext,
-) -> None:
- page = await context.new_page()
- async with page.expect_popup() as popup_info:
- await page.evaluate(
- """() => {
- win = window.open('about:blank')
- win.close()
- }"""
- )
- popup = await popup_info.value
- assert popup
-
-
-async def test_should_emit_for_immediately_closed_popups(
- context: BrowserContext, server: Server
-) -> None:
- page = await context.new_page()
- await page.goto(server.EMPTY_PAGE)
- async with page.expect_popup() as popup_info:
- await page.evaluate(
- """() => {
- win = window.open(window.location.href)
- win.close()
- }"""
- )
- popup = await popup_info.value
- assert popup
-
-
-async def test_should_be_able_to_capture_alert(context: BrowserContext) -> None:
- page = await context.new_page()
- evaluate_task: Optional[asyncio.Future] = None
-
- async def evaluate() -> None:
- nonlocal evaluate_task
- evaluate_task = asyncio.create_task(
- page.evaluate(
- """() => {
- const win = window.open('')
- win.alert('hello')
- }"""
- )
- )
-
- [popup, dialog, _] = await asyncio.gather(
- page.wait_for_event("popup"), context.wait_for_event("dialog"), evaluate()
- )
-
- assert dialog.message == "hello"
- assert dialog.page == popup
- await dialog.dismiss()
- await must(evaluate_task)
-
-
-async def test_should_work_with_empty_url(context: BrowserContext) -> None:
- page = await context.new_page()
- async with page.expect_popup() as popup_info:
- await page.evaluate("() => window.__popup = window.open('')")
- popup = await popup_info.value
- assert await page.evaluate("!!window.opener") is False
- assert await popup.evaluate("!!window.opener")
-
-
-async def test_should_work_with_noopener_and_no_url(context: BrowserContext) -> None:
- page = await context.new_page()
- async with page.expect_popup() as popup_info:
- await page.evaluate('() => window.__popup = window.open(undefined, null, "noopener")')
- popup = await popup_info.value
- # Chromium reports 'about:blank#blocked' here.
- assert popup.url.split("#")[0] == "about:blank"
- assert await page.evaluate("!!window.opener") is False
- assert await popup.evaluate("!!window.opener") is False
-
-
-async def test_should_work_with_noopener_and_about_blank(
- context: BrowserContext,
-) -> None:
- page = await context.new_page()
- async with page.expect_popup() as popup_info:
- await page.evaluate('() => window.__popup = window.open("about:blank", null, "noopener")')
- popup = await popup_info.value
- assert await page.evaluate("!!window.opener") is False
- assert await popup.evaluate("!!window.opener") is False
-
-
-async def test_should_work_with_noopener_and_url(context: BrowserContext, server: Server) -> None:
- page = await context.new_page()
- await page.goto(server.EMPTY_PAGE)
- async with page.expect_popup() as popup_info:
- await page.evaluate(
- 'url => window.__popup = window.open(url, null, "noopener")',
- server.EMPTY_PAGE,
- )
- popup = await popup_info.value
- assert await page.evaluate("!!window.opener") is False
- assert await popup.evaluate("!!window.opener") is False
-
-
-async def test_should_work_with_clicking_target__blank(
- context: BrowserContext, server: Server
-) -> None:
- page = await context.new_page()
- await page.goto(server.EMPTY_PAGE)
- await page.set_content('yo ')
- async with page.expect_popup() as popup_info:
- await page.click("a")
- popup = await popup_info.value
- assert await page.evaluate("!!window.opener") is False
- assert await popup.evaluate("!!window.opener")
- assert popup.main_frame.page == popup
-
-
-async def test_should_work_with_fake_clicking_target__blank_and_rel_noopener(
- context: BrowserContext, server: Server
-) -> None:
- page = await context.new_page()
- await page.goto(server.EMPTY_PAGE)
- await page.set_content('yo ')
- async with page.expect_popup() as popup_info:
- await page.eval_on_selector("a", "a => a.click()")
- popup = await popup_info.value
- assert await page.evaluate("!!window.opener") is False
- assert await popup.evaluate("!!window.opener") is False
-
-
-async def test_should_work_with_clicking_target__blank_and_rel_noopener(
- context: BrowserContext, server: Server
-) -> None:
- page = await context.new_page()
- await page.goto(server.EMPTY_PAGE)
- await page.set_content('yo ')
- async with page.expect_popup() as popup_info:
- await page.click("a")
- popup = await popup_info.value
- assert await page.evaluate("!!window.opener") is False
- assert await popup.evaluate("!!window.opener") is False
-
-
-async def test_should_not_treat_navigations_as_new_popups(
- context: BrowserContext, server: Server
-) -> None:
- page = await context.new_page()
- await page.goto(server.EMPTY_PAGE)
- await page.set_content('yo ')
- async with page.expect_popup() as popup_info:
- await page.click("a")
- popup = await popup_info.value
- handled_popups = []
- page.on(
- "popup",
- lambda popup: handled_popups.append(True),
- )
-
- await popup.goto(server.CROSS_PROCESS_PREFIX + "/empty.html")
- assert len(handled_popups) == 0
diff --git a/tests/async/test_proxy.py b/tests/async/test_proxy.py
deleted file mode 100644
index 59b99ff..0000000
--- a/tests/async/test_proxy.py
+++ /dev/null
@@ -1,131 +0,0 @@
-# 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 base64
-from typing import Callable
-
-import pytest
-
-from playwright.async_api import Browser, Error
-from tests.server import Server, TestServerRequest
-
-
-async def test_should_throw_for_bad_server_value(
- browser_factory: "Callable[..., asyncio.Future[Browser]]",
-) -> None:
- with pytest.raises(Error) as exc_info:
- await browser_factory(proxy={"server": 123})
- assert "proxy.server: expected string, got number" in exc_info.value.message
-
-
-async def test_should_use_proxy(
- browser_factory: "Callable[..., asyncio.Future[Browser]]", server: Server
-) -> None:
- server.set_route(
- "/target.html",
- lambda r: (
- r.write(b"Served by the proxy "),
- r.finish(),
- ),
- )
- browser = await browser_factory(proxy={"server": f"localhost:{server.PORT}"})
- page = await browser.new_page()
- await page.goto("http://non-existent.com/target.html")
- assert await page.title() == "Served by the proxy"
-
-
-async def test_should_use_proxy_for_second_page(
- browser_factory: "Callable[..., asyncio.Future[Browser]]", server: Server
-) -> None:
- server.set_route(
- "/target.html",
- lambda r: (
- r.write(b"Served by the proxy "),
- r.finish(),
- ),
- )
- browser = await browser_factory(proxy={"server": f"localhost:{server.PORT}"})
-
- page1 = await browser.new_page()
- await page1.goto("http://non-existent.com/target.html")
- assert await page1.title() == "Served by the proxy"
-
- page2 = await browser.new_page()
- await page2.goto("http://non-existent.com/target.html")
- assert await page2.title() == "Served by the proxy"
-
-
-async def test_should_work_with_ip_port_notion(
- browser_factory: "Callable[..., asyncio.Future[Browser]]", server: Server
-) -> None:
- server.set_route(
- "/target.html",
- lambda r: (
- r.write(b"Served by the proxy "),
- r.finish(),
- ),
- )
- browser = await browser_factory(proxy={"server": f"127.0.0.1:{server.PORT}"})
- page = await browser.new_page()
- await page.goto("http://non-existent.com/target.html")
- assert await page.title() == "Served by the proxy"
-
-
-async def test_should_authenticate(
- browser_factory: "Callable[..., asyncio.Future[Browser]]", server: Server
-) -> None:
- def handler(req: TestServerRequest) -> None:
- auth = req.getHeader("proxy-authorization")
- if not auth:
- req.setHeader(b"Proxy-Authenticate", b'Basic realm="Access to internal site"')
- req.setResponseCode(407)
- else:
- req.write(f"{auth} ".encode("utf-8"))
- req.finish()
-
- server.set_route("/target.html", handler)
-
- browser = await browser_factory(
- proxy={
- "server": f"localhost:{server.PORT}",
- "username": "user",
- "password": "secret",
- }
- )
- page = await browser.new_page()
- await page.goto("http://non-existent.com/target.html")
- assert await page.title() == "Basic " + base64.b64encode(b"user:secret").decode("utf-8")
-
-
-async def test_should_authenticate_with_empty_password(
- browser_factory: "Callable[..., asyncio.Future[Browser]]", server: Server
-) -> None:
- def handler(req: TestServerRequest) -> None:
- auth = req.getHeader("proxy-authorization")
- if not auth:
- req.setHeader(b"Proxy-Authenticate", b'Basic realm="Access to internal site"')
- req.setResponseCode(407)
- else:
- req.write(f"{auth} ".encode("utf-8"))
- req.finish()
-
- server.set_route("/target.html", handler)
-
- browser = await browser_factory(
- proxy={"server": f"localhost:{server.PORT}", "username": "user", "password": ""}
- )
- page = await browser.new_page()
- await page.goto("http://non-existent.com/target.html")
- assert await page.title() == "Basic " + base64.b64encode(b"user:").decode("utf-8")
diff --git a/tests/async/test_queryselector.py b/tests/async/test_queryselector.py
deleted file mode 100644
index 69fccf4..0000000
--- a/tests/async/test_queryselector.py
+++ /dev/null
@@ -1,352 +0,0 @@
-# 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.
-from pathlib import Path
-
-import pytest
-
-from playwright.async_api import Browser, Error, Page, Selectors
-
-from .utils import Utils
-
-
-async def test_selectors_register_should_work(
- selectors: Selectors, browser: Browser, browser_name: str
-) -> None:
- tag_selector = """
- {
- create(root, target) {
- return target.nodeName;
- },
- query(root, selector) {
- return root.querySelector(selector);
- },
- queryAll(root, selector) {
- return Array.from(root.querySelectorAll(selector));
- }
- }"""
-
- selector_name = f"tag_{browser_name}"
- selector2_name = f"tag2_{browser_name}"
-
- # Register one engine before creating context.
- await selectors.register(selector_name, tag_selector)
-
- context = await browser.new_context()
- # Register another engine after creating context.
- await selectors.register(selector2_name, tag_selector)
-
- page = await context.new_page()
- await page.set_content("
")
-
- assert await page.eval_on_selector(f"{selector_name}=DIV", "e => e.nodeName") == "DIV"
- assert await page.eval_on_selector(f"{selector_name}=SPAN", "e => e.nodeName") == "SPAN"
- assert await page.eval_on_selector_all(f"{selector_name}=DIV", "es => es.length") == 2
-
- assert await page.eval_on_selector(f"{selector2_name}=DIV", "e => e.nodeName") == "DIV"
- assert await page.eval_on_selector(f"{selector2_name}=SPAN", "e => e.nodeName") == "SPAN"
- assert await page.eval_on_selector_all(f"{selector2_name}=DIV", "es => es.length") == 2
-
- # Selector names are case-sensitive.
- with pytest.raises(Error) as exc:
- await page.query_selector("tAG=DIV")
- assert 'Unknown engine "tAG" while parsing selector tAG=DIV' in exc.value.message
-
- await context.close()
-
-
-async def test_selectors_register_should_work_with_path(
- selectors: Selectors, page: Page, utils: Utils, assetdir: Path
-) -> None:
- await utils.register_selector_engine(
- selectors, "foo", path=assetdir / "sectionselectorengine.js"
- )
- await page.set_content("")
- assert await page.eval_on_selector("foo=whatever", "e => e.nodeName") == "SECTION"
-
-
-async def test_selectors_register_should_work_in_main_and_isolated_world(
- selectors: Selectors, page: Page, utils: Utils
-) -> None:
- dummy_selector_script = """{
- create(root, target) { },
- query(root, selector) {
- return window.__answer;
- },
- queryAll(root, selector) {
- return window['__answer'] ? [window['__answer'], document.body, document.documentElement] : [];
- }
- }"""
-
- await utils.register_selector_engine(selectors, "main", dummy_selector_script)
- await utils.register_selector_engine(
- selectors, "isolated", dummy_selector_script, content_script=True
- )
- await page.set_content("
")
- await page.evaluate('() => window.__answer = document.querySelector("span")')
- # Works in main if asked.
- assert await page.eval_on_selector("main=ignored", "e => e.nodeName") == "SPAN"
- assert await page.eval_on_selector("css=div >> main=ignored", "e => e.nodeName") == "SPAN"
- assert await page.eval_on_selector_all("main=ignored", "es => window.__answer !== undefined")
- assert await page.eval_on_selector_all("main=ignored", "es => es.filter(e => e).length") == 3
- # Works in isolated by default.
- assert await page.query_selector("isolated=ignored") is None
- assert await page.query_selector("css=div >> isolated=ignored") is None
- # $$eval always works in main, to avoid adopting nodes one by one.
- assert await page.eval_on_selector_all(
- "isolated=ignored", "es => window.__answer !== undefined"
- )
- assert (
- await page.eval_on_selector_all("isolated=ignored", "es => es.filter(e => e).length") == 3
- )
- # At least one engine in main forces all to be in main.
- assert (
- await page.eval_on_selector("main=ignored >> isolated=ignored", "e => e.nodeName") == "SPAN"
- )
- assert (
- await page.eval_on_selector("isolated=ignored >> main=ignored", "e => e.nodeName") == "SPAN"
- )
- # Can be chained to css.
- assert (
- await page.eval_on_selector("main=ignored >> css=section", "e => e.nodeName") == "SECTION"
- )
-
-
-async def test_selectors_register_should_handle_errors(
- selectors: Selectors, page: Page, utils: Utils
-) -> None:
- with pytest.raises(Error) as exc:
- await page.query_selector("neverregister=ignored")
- assert (
- 'Unknown engine "neverregister" while parsing selector neverregister=ignored'
- in exc.value.message
- )
-
- dummy_selector_engine_script = """{
- create(root, target) {
- return target.nodeName;
- },
- query(root, selector) {
- return root.querySelector('dummy');
- },
- queryAll(root, selector) {
- return Array.from(root.query_selector_all('dummy'));
- }
- }"""
-
- with pytest.raises(Error) as exc:
- await selectors.register("$", dummy_selector_engine_script)
- assert (
- exc.value.message
- == "Selectors.register: Selector engine name may only contain [a-zA-Z0-9_] characters"
- )
-
- # Selector names are case-sensitive.
- await utils.register_selector_engine(selectors, "dummy", dummy_selector_engine_script)
- await utils.register_selector_engine(selectors, "duMMy", dummy_selector_engine_script)
-
- with pytest.raises(Error) as exc:
- await selectors.register("dummy", dummy_selector_engine_script)
- assert (
- exc.value.message
- == 'Selectors.register: "dummy" selector engine has been already registered'
- )
-
- with pytest.raises(Error) as exc:
- await selectors.register("css", dummy_selector_engine_script)
- assert exc.value.message == 'Selectors.register: "css" is a predefined selector engine'
-
-
-async def test_should_work_with_layout_selectors(page: Page) -> None:
- # +--+ +--+
- # | 1| | 2|
- # +--+ ++-++
- # | 3| | 4|
- # +-------+ ++-++
- # | 0 | | 5|
- # | +--+ +--+--+
- # | | 6| | 7|
- # | +--+ +--+
- # | |
- # O-------+
- # +--+
- # | 8|
- # +--++--+
- # | 9|
- # +--+
-
- boxes = [
- # x, y, width, height
- [0, 0, 150, 150],
- [100, 200, 50, 50],
- [200, 200, 50, 50],
- [100, 150, 50, 50],
- [201, 150, 50, 50],
- [200, 100, 50, 50],
- [50, 50, 50, 50],
- [150, 50, 50, 50],
- [150, -51, 50, 50],
- [201, -101, 50, 50],
- ]
- await page.set_content(
- ' '
- )
- await page.eval_on_selector(
- "container",
- """(container, boxes) => {
- for (let i = 0; i < boxes.length; i++) {
- const div = document.createElement('div');
- div.style.position = 'absolute';
- div.style.overflow = 'hidden';
- div.style.boxSizing = 'border-box';
- div.style.border = '1px solid black';
- div.id = 'id' + i;
- div.textContent = 'id' + i;
- const box = boxes[i];
- div.style.left = box[0] + 'px';
- // Note that top is a flipped y coordinate.
- div.style.top = (250 - box[1] - box[3]) + 'px';
- div.style.width = box[2] + 'px';
- div.style.height = box[3] + 'px';
- container.appendChild(div);
- const span = document.createElement('span');
- span.textContent = '' + i;
- div.appendChild(span);
- }
- }""",
- boxes,
- )
-
- assert await page.eval_on_selector("div:right-of(#id6)", "e => e.id") == "id7"
- assert await page.eval_on_selector("div:right-of(#id1)", "e => e.id") == "id2"
- assert await page.eval_on_selector("div:right-of(#id3)", "e => e.id") == "id4"
- assert await page.query_selector("div:right-of(#id4)") is None
- assert await page.eval_on_selector("div:right-of(#id0)", "e => e.id") == "id7"
- assert await page.eval_on_selector("div:right-of(#id8)", "e => e.id") == "id9"
- assert (
- await page.eval_on_selector_all("div:right-of(#id3)", "els => els.map(e => e.id).join(',')")
- == "id4,id2,id5,id7,id8,id9"
- )
- assert (
- await page.eval_on_selector_all(
- "div:right-of(#id3, 50)", "els => els.map(e => e.id).join(',')"
- )
- == "id2,id5,id7,id8"
- )
- assert (
- await page.eval_on_selector_all(
- "div:right-of(#id3, 49)", "els => els.map(e => e.id).join(',')"
- )
- == "id7,id8"
- )
-
- assert await page.eval_on_selector("div:left-of(#id2)", "e => e.id") == "id1"
- assert await page.query_selector("div:left-of(#id0)") is None
- assert await page.eval_on_selector("div:left-of(#id5)", "e => e.id") == "id0"
- assert await page.eval_on_selector("div:left-of(#id9)", "e => e.id") == "id8"
- assert await page.eval_on_selector("div:left-of(#id4)", "e => e.id") == "id3"
- assert (
- await page.eval_on_selector_all("div:left-of(#id5)", "els => els.map(e => e.id).join(',')")
- == "id0,id7,id3,id1,id6,id8"
- )
- assert (
- await page.eval_on_selector_all(
- "div:left-of(#id5, 3)", "els => els.map(e => e.id).join(',')"
- )
- == "id7,id8"
- )
-
- assert await page.eval_on_selector("div:above(#id0)", "e => e.id") == "id3"
- assert await page.eval_on_selector("div:above(#id5)", "e => e.id") == "id4"
- assert await page.eval_on_selector("div:above(#id7)", "e => e.id") == "id5"
- assert await page.eval_on_selector("div:above(#id8)", "e => e.id") == "id0"
- assert await page.eval_on_selector("div:above(#id9)", "e => e.id") == "id8"
- assert await page.query_selector("div:above(#id2)") is None
- assert (
- await page.eval_on_selector_all("div:above(#id5)", "els => els.map(e => e.id).join(',')")
- == "id4,id2,id3,id1"
- )
- assert (
- await page.eval_on_selector_all(
- "div:above(#id5, 20)", "els => els.map(e => e.id).join(',')"
- )
- == "id4,id3"
- )
-
- assert await page.eval_on_selector("div:below(#id4)", "e => e.id") == "id5"
- assert await page.eval_on_selector("div:below(#id3)", "e => e.id") == "id0"
- assert await page.eval_on_selector("div:below(#id2)", "e => e.id") == "id4"
- assert await page.eval_on_selector("div:below(#id6)", "e => e.id") == "id8"
- assert await page.eval_on_selector("div:below(#id7)", "e => e.id") == "id8"
- assert await page.eval_on_selector("div:below(#id8)", "e => e.id") == "id9"
- assert await page.query_selector("div:below(#id9)") is None
- assert (
- await page.eval_on_selector_all("div:below(#id3)", "els => els.map(e => e.id).join(',')")
- == "id0,id5,id6,id7,id8,id9"
- )
- assert (
- await page.eval_on_selector_all(
- "div:below(#id3, 105)", "els => els.map(e => e.id).join(',')"
- )
- == "id0,id5,id6,id7"
- )
-
- assert await page.eval_on_selector("div:near(#id0)", "e => e.id") == "id3"
- assert (
- await page.eval_on_selector_all("div:near(#id7)", "els => els.map(e => e.id).join(',')")
- == "id0,id5,id3,id6"
- )
- assert (
- await page.eval_on_selector_all("div:near(#id0)", "els => els.map(e => e.id).join(',')")
- == "id3,id6,id7,id8,id1,id5"
- )
- assert (
- await page.eval_on_selector_all("div:near(#id6)", "els => els.map(e => e.id).join(',')")
- == "id0,id3,id7"
- )
- assert (
- await page.eval_on_selector_all("div:near(#id6, 10)", "els => els.map(e => e.id).join(',')")
- == "id0"
- )
- assert (
- await page.eval_on_selector_all(
- "div:near(#id0, 100)", "els => els.map(e => e.id).join(',')"
- )
- == "id3,id6,id7,id8,id1,id5,id4,id2"
- )
-
- assert (
- await page.eval_on_selector_all(
- "div:below(#id5):above(#id8)", "els => els.map(e => e.id).join(',')"
- )
- == "id7,id6"
- )
- assert await page.eval_on_selector("div:below(#id5):above(#id8)", "e => e.id") == "id7"
-
- assert (
- await page.eval_on_selector_all(
- "div:right-of(#id0) + div:above(#id8)",
- "els => els.map(e => e.id).join(',')",
- )
- == "id5,id6,id3"
- )
-
- with pytest.raises(Error) as exc_info:
- await page.query_selector(":near(50)")
- assert (
- '"near" engine expects a selector list and optional maximum distance in pixels'
- in exc_info.value.message
- )
- with pytest.raises(Error) as exc_info:
- await page.query_selector('left-of="div"')
- assert '"left-of" selector cannot be first' in exc_info.value.message
diff --git a/tests/async/test_request_continue.py b/tests/async/test_request_continue.py
deleted file mode 100644
index 17d21ae..0000000
--- a/tests/async/test_request_continue.py
+++ /dev/null
@@ -1,186 +0,0 @@
-# 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
-from typing import Optional
-
-from playwright.async_api import Page, Route
-from tests.server import Server, TestServerRequest
-
-
-async def test_request_continue_should_work(page: Page, server: Server) -> None:
- await page.route("**/*", lambda route: asyncio.create_task(route.continue_()))
- await page.goto(server.EMPTY_PAGE)
-
-
-async def test_request_continue_should_amend_http_headers(page: Page, server: Server) -> None:
- await page.route(
- "**/*",
- lambda route: asyncio.create_task(
- route.continue_(headers={**route.request.headers, "FOO": "bar"})
- ),
- )
-
- await page.goto(server.EMPTY_PAGE)
- [request, _] = await asyncio.gather(
- server.wait_for_request("/sleep.zzz"),
- page.evaluate('() => fetch("/sleep.zzz")'),
- )
- assert request.getHeader("foo") == "bar"
-
-
-async def test_request_continue_should_amend_method(page: Page, server: Server) -> None:
- server_request = asyncio.create_task(server.wait_for_request("/sleep.zzz"))
- await page.goto(server.EMPTY_PAGE)
- await page.route("**/*", lambda route: asyncio.create_task(route.continue_(method="POST")))
- [request, _] = await asyncio.gather(
- server.wait_for_request("/sleep.zzz"),
- page.evaluate('() => fetch("/sleep.zzz")'),
- )
- assert request.method.decode() == "POST"
- assert (await server_request).method.decode() == "POST"
-
-
-async def test_request_continue_should_amend_method_on_main_request(
- page: Page, server: Server
-) -> None:
- request = asyncio.create_task(server.wait_for_request("/empty.html"))
- await page.route("**/*", lambda route: asyncio.create_task(route.continue_(method="POST")))
- await page.goto(server.EMPTY_PAGE)
- assert (await request).method.decode() == "POST"
-
-
-async def test_request_continue_should_amend_post_data(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- await page.route(
- "**/*",
- lambda route: asyncio.create_task(route.continue_(post_data=b"doggo")),
- )
-
- [server_request, _] = await asyncio.gather(
- server.wait_for_request("/sleep.zzz"),
- page.evaluate(
- """
- () => fetch('/sleep.zzz', { method: 'POST', body: 'birdy' })
- """
- ),
- )
- assert server_request.post_body
- assert server_request.post_body.decode() == "doggo"
-
-
-async def test_should_override_request_url(page: Page, server: Server) -> None:
- request = asyncio.create_task(server.wait_for_request("/empty.html"))
- await page.route(
- "**/foo",
- lambda route: asyncio.create_task(route.continue_(url=server.EMPTY_PAGE)),
- )
-
- await page.goto(server.PREFIX + "/foo")
- assert (await request).method == b"GET"
-
-
-async def test_should_raise_except(page: Page, server: Server) -> None:
- exc_fut: "asyncio.Future[Optional[Exception]]" = asyncio.Future()
-
- async def capture_exception(route: Route) -> None:
- try:
- await route.continue_(url="file:///tmp/does-not-exist")
- exc_fut.set_result(None)
- except Exception as e:
- exc_fut.set_result(e)
-
- await page.route("**/*", capture_exception)
- asyncio.create_task(page.goto(server.EMPTY_PAGE))
- assert "New URL must have same protocol as overridden URL" in str(await exc_fut)
-
-
-async def test_should_amend_utf8_post_data(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- await page.route(
- "**/*",
- lambda route: asyncio.create_task(route.continue_(post_data="пушкин")),
- )
-
- [server_request, result] = await asyncio.gather(
- server.wait_for_request("/sleep.zzz"),
- page.evaluate("fetch('/sleep.zzz', { method: 'POST', body: 'birdy' })"),
- )
- assert server_request.method == b"POST"
- assert server_request.post_body
- assert server_request.post_body.decode("utf8") == "пушкин"
-
-
-async def test_should_amend_binary_post_data(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- await page.route(
- "**/*",
- lambda route: asyncio.create_task(route.continue_(post_data=b"\x00\x01\x02\x03\x04")),
- )
-
- [server_request, result] = await asyncio.gather(
- server.wait_for_request("/sleep.zzz"),
- page.evaluate("fetch('/sleep.zzz', { method: 'POST', body: 'birdy' })"),
- )
- assert server_request.method == b"POST"
- assert server_request.post_body == b"\x00\x01\x02\x03\x04"
-
-
-async def test_continue_should_not_change_multipart_form_data_body(
- page: Page, server: Server, browser_name: str
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- server.set_route(
- "/upload",
- lambda context: (
- context.write(b"done"),
- context.setHeader("Content-Type", "text/plain"),
- context.finish(),
- ),
- )
-
- async def send_form_data() -> TestServerRequest:
- req_task = asyncio.create_task(server.wait_for_request("/upload"))
- status = await page.evaluate(
- """async () => {
- const newFile = new File(['file content'], 'file.txt');
- const formData = new FormData();
- formData.append('file', newFile);
- const response = await fetch('/upload', {
- method: 'POST',
- credentials: 'include',
- body: formData,
- });
- return response.status;
- }"""
- )
- req = await req_task
- assert status == 200
- return req
-
- req_before = await send_form_data()
- await page.route("**/*", lambda route: route.continue_())
- req_after = await send_form_data()
-
- file_content = (
- 'Content-Disposition: form-data; name="file"; filename="file.txt"\r\n'
- "Content-Type: application/octet-stream\r\n"
- "\r\n"
- "file content\r\n"
- "------"
- )
- assert req_before.post_body
- assert req_after.post_body
- assert file_content in req_before.post_body.decode()
- assert file_content in req_after.post_body.decode()
diff --git a/tests/async/test_request_fulfill.py b/tests/async/test_request_fulfill.py
deleted file mode 100644
index 4f6739b..0000000
--- a/tests/async/test_request_fulfill.py
+++ /dev/null
@@ -1,71 +0,0 @@
-# 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.
-
-from playwright.async_api import Page, Route
-from tests.server import Server
-
-
-async def test_should_fetch_original_request_and_fulfill(page: Page, server: Server) -> None:
- async def handle(route: Route) -> None:
- response = await page.request.fetch(route.request)
- await route.fulfill(response=response)
-
- await page.route("**/*", handle)
- response = await page.goto(server.PREFIX + "/title.html")
- assert response
- assert response.status == 200
- assert await page.title() == "Woof-Woof"
-
-
-async def test_should_fulfill_json(page: Page, server: Server) -> None:
- async def handle(route: Route) -> None:
- await route.fulfill(status=201, headers={"foo": "bar"}, json={"bar": "baz"})
-
- await page.route("**/*", handle)
-
- response = await page.goto(server.EMPTY_PAGE)
- assert response
- assert response.status == 201
- assert response.headers["content-type"] == "application/json"
- assert await response.json() == {"bar": "baz"}
-
-
-async def test_should_fulfill_json_overriding_existing_response(page: Page, server: Server) -> None:
- server.set_route(
- "/tags",
- lambda request: (
- request.setHeader("foo", "bar"),
- request.write('{"tags": ["a", "b"]}'.encode()),
- request.finish(),
- ),
- )
-
- original = {}
-
- async def handle(route: Route) -> None:
- response = await route.fetch()
- json = await response.json()
- original["tags"] = json["tags"]
- json["tags"] = ["c"]
- await route.fulfill(response=response, json=json)
-
- await page.route("**/*", handle)
-
- response = await page.goto(server.PREFIX + "/tags")
- assert response
- assert response.status == 200
- assert response.headers["content-type"] == "application/json"
- assert response.headers["foo"] == "bar"
- assert original["tags"] == ["a", "b"]
- assert await response.json() == {"tags": ["c"]}
diff --git a/tests/async/test_request_intercept.py b/tests/async/test_request_intercept.py
deleted file mode 100644
index 910ded7..0000000
--- a/tests/async/test_request_intercept.py
+++ /dev/null
@@ -1,171 +0,0 @@
-# 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
-from pathlib import Path
-
-from twisted.web import http
-
-from playwright.async_api import Page, Route
-from tests.server import Server
-
-
-async def test_should_fulfill_intercepted_response(page: Page, server: Server) -> None:
- async def handle(route: Route) -> None:
- response = await page.request.fetch(route.request)
- await route.fulfill(
- response=response,
- status=201,
- headers={"foo": "bar"},
- content_type="text/plain",
- body="Yo, page!",
- )
-
- await page.route("**/*", handle)
- response = await page.goto(server.PREFIX + "/empty.html")
- assert response
- assert response.status == 201
- assert response.headers["foo"] == "bar"
- assert response.headers["content-type"] == "text/plain"
- assert await page.evaluate("() => document.body.textContent") == "Yo, page!"
-
-
-async def test_should_fulfill_response_with_empty_body(page: Page, server: Server) -> None:
- async def handle(route: Route) -> None:
- response = await page.request.fetch(route.request)
- await route.fulfill(response=response, status=201, body="", headers={"content-length": "0"})
-
- await page.route("**/*", handle)
- response = await page.goto(server.PREFIX + "/title.html")
- assert response
- assert response.status == 201
- assert await response.text() == ""
-
-
-async def test_should_override_with_defaults_when_intercepted_response_not_provided(
- page: Page, server: Server, browser_name: str
-) -> None:
- def server_handler(request: http.Request) -> None:
- request.setHeader("foo", "bar")
- request.write("my content".encode())
- request.finish()
-
- server.set_route("/empty.html", server_handler)
-
- async def handle(route: Route) -> None:
- await page.request.fetch(route.request)
- await route.fulfill(status=201)
-
- await page.route("**/*", handle)
- response = await page.goto(server.EMPTY_PAGE)
- assert response
- assert response.status == 201
- assert await response.text() == ""
- if browser_name == "webkit":
- assert response.headers == {"content-type": "text/plain"}
- else:
- assert response.headers == {}
-
-
-async def test_should_fulfill_with_any_response(page: Page, server: Server) -> None:
- def server_handler(request: http.Request) -> None:
- request.setHeader("foo", "bar")
- request.write("Woo-hoo".encode())
- request.finish()
-
- server.set_route("/sample", server_handler)
- sample_response = await page.request.get(server.PREFIX + "/sample")
- await page.route(
- "**/*",
- lambda route: route.fulfill(
- response=sample_response, status=201, content_type="text/plain"
- ),
- )
- response = await page.goto(server.EMPTY_PAGE)
- assert response
- assert response.status == 201
- assert await response.text() == "Woo-hoo"
- assert response.headers["foo"] == "bar"
-
-
-async def test_should_support_fulfill_after_intercept(
- page: Page, server: Server, assetdir: Path
-) -> None:
- request_future = asyncio.create_task(server.wait_for_request("/title.html"))
-
- async def handle_route(route: Route) -> None:
- response = await page.request.fetch(route.request)
- await route.fulfill(response=response)
-
- await page.route("**", handle_route)
- response = await page.goto(server.PREFIX + "/title.html")
- assert response
- request = await request_future
- assert request.uri.decode() == "/title.html"
- original = (assetdir / "title.html").read_text()
- assert await response.text() == original
-
-
-async def test_should_give_access_to_the_intercepted_response(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
-
- route_task: "asyncio.Future[Route]" = asyncio.Future()
- await page.route("**/title.html", lambda route: route_task.set_result(route))
-
- eval_task = asyncio.create_task(
- page.evaluate("url => fetch(url)", server.PREFIX + "/title.html")
- )
-
- route = await route_task
- response = await page.request.fetch(route.request)
-
- assert response.status == 200
- assert response.status_text == "OK"
- assert response.ok is True
- assert response.url.endswith("/title.html") is True
- assert response.headers["content-type"] == "text/html; charset=utf-8"
- assert list(
- filter(
- lambda header: header["name"].lower() == "content-type",
- response.headers_array,
- )
- ) == [{"name": "Content-Type", "value": "text/html; charset=utf-8"}]
-
- await asyncio.gather(
- route.fulfill(response=response),
- eval_task,
- )
-
-
-async def test_should_give_access_to_the_intercepted_response_body(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
-
- route_task: "asyncio.Future[Route]" = asyncio.Future()
- await page.route("**/simple.json", lambda route: route_task.set_result(route))
-
- eval_task = asyncio.create_task(
- page.evaluate("url => fetch(url)", server.PREFIX + "/simple.json")
- )
-
- route = await route_task
- response = await page.request.fetch(route.request)
-
- assert await response.text() == '{"foo": "bar"}\n'
-
- await asyncio.gather(
- route.fulfill(response=response),
- eval_task,
- )
diff --git a/tests/async/test_resource_timing.py b/tests/async/test_resource_timing.py
deleted file mode 100644
index 2a14414..0000000
--- a/tests/async/test_resource_timing.py
+++ /dev/null
@@ -1,106 +0,0 @@
-# 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.
-
-from typing import Dict
-
-import pytest
-from flaky import flaky
-
-from playwright.async_api import Browser, Page
-from tests.server import Server
-
-
-async def test_should_work(page: Page, server: Server) -> None:
- async with page.expect_event("requestfinished") as request_info:
- await page.goto(server.EMPTY_PAGE)
- request = await request_info.value
- timing = request.timing
- verify_connections_timing_consistency(timing)
- assert timing["requestStart"] >= timing["connectEnd"]
- assert timing["responseStart"] >= timing["requestStart"]
- assert timing["responseEnd"] >= timing["responseStart"]
- assert timing["responseEnd"] < 10000
-
-
-@flaky
-async def test_should_work_for_subresource(
- page: Page, server: Server, is_win: bool, is_mac: bool, is_webkit: bool
-) -> None:
- if is_webkit and (is_mac or is_win):
- pytest.skip()
- requests = []
- page.on("requestfinished", lambda request: requests.append(request))
- await page.goto(server.PREFIX + "/one-style.html")
- assert len(requests) >= 2
- timing = requests[1].timing
- verify_connections_timing_consistency(timing)
- assert timing["requestStart"] >= 0
- assert timing["responseStart"] > timing["requestStart"]
- assert timing["responseEnd"] >= timing["responseStart"]
- assert timing["responseEnd"] < 10000
-
-
-@flaky # Upstream flaky
-async def test_should_work_for_ssl(browser: Browser, https_server: Server) -> None:
- page = await browser.new_page(ignore_https_errors=True)
- async with page.expect_event("requestfinished") as request_info:
- await page.goto(https_server.EMPTY_PAGE)
- request = await request_info.value
- timing = request.timing
- verify_connections_timing_consistency(timing)
- assert timing["requestStart"] >= timing["connectEnd"]
- assert timing["responseStart"] >= timing["requestStart"]
- assert timing["responseEnd"] >= timing["responseStart"]
- assert timing["responseEnd"] < 10000
- await page.close()
-
-
-@pytest.mark.skip_browser("webkit") # In WebKit, redirects don"t carry the timing info
-async def test_should_work_for_redirect(page: Page, server: Server) -> None:
- server.set_redirect("/foo.html", "/empty.html")
- responses = []
- page.on("response", lambda response: responses.append(response))
- await page.goto(server.PREFIX + "/foo.html")
- for r in responses:
- await r.finished()
-
- assert len(responses) == 2
- assert responses[0].url == server.PREFIX + "/foo.html"
- assert responses[1].url == server.PREFIX + "/empty.html"
-
- timing1 = responses[0].request.timing
- verify_connections_timing_consistency(timing1)
- assert timing1["requestStart"] >= timing1["connectEnd"]
- assert timing1["responseStart"] > timing1["requestStart"]
- assert timing1["responseEnd"] >= timing1["responseStart"]
- assert timing1["responseEnd"] < 10000
-
- timing2 = responses[1].request.timing
- verify_connections_timing_consistency(timing2)
- assert timing2["requestStart"] >= 0
- assert timing2["responseStart"] > timing2["requestStart"]
- assert timing2["responseEnd"] >= timing2["responseStart"]
- assert timing2["responseEnd"] < 10000
-
-
-def verify_timing_value(value: float, previous: float) -> None:
- assert value == -1 or value > 0 and value >= previous
-
-
-def verify_connections_timing_consistency(timing: Dict) -> None:
- verify_timing_value(timing["domainLookupStart"], -1)
- verify_timing_value(timing["domainLookupEnd"], timing["domainLookupStart"])
- verify_timing_value(timing["connectStart"], timing["domainLookupEnd"])
- verify_timing_value(timing["secureConnectionStart"], timing["connectStart"])
- verify_timing_value(timing["connectEnd"], timing["secureConnectionStart"])
diff --git a/tests/async/test_screenshot.py b/tests/async/test_screenshot.py
deleted file mode 100644
index b7c679a..0000000
--- a/tests/async/test_screenshot.py
+++ /dev/null
@@ -1,44 +0,0 @@
-# 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.
-
-from typing import Callable
-
-from playwright.async_api import Page
-
-from tests.server import Server
-from tests.utils import must
-
-
-async def test_should_screenshot_with_mask(
- page: Page, server: Server, assert_to_be_golden: Callable[[bytes, str], None]
-) -> None:
- await page.set_viewport_size(
- {
- "width": 500,
- "height": 500,
- }
- )
- await page.goto(server.PREFIX + "/grid.html")
- assert_to_be_golden(
- await page.screenshot(mask=[page.locator("div").nth(5)]),
- "mask-should-work-with-page.png",
- )
- assert_to_be_golden(
- await page.locator("body").screenshot(mask=[page.locator("div").nth(5)]),
- "mask-should-work-with-locator.png",
- )
- assert_to_be_golden(
- await must(await page.query_selector("body")).screenshot(mask=[page.locator("div").nth(5)]),
- "mask-should-work-with-element-handle.png",
- )
diff --git a/tests/async/test_selector_generator.py b/tests/async/test_selector_generator.py
deleted file mode 100644
index 10b0729..0000000
--- a/tests/async/test_selector_generator.py
+++ /dev/null
@@ -1,48 +0,0 @@
-# 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 pytest
-
-from playwright.async_api import Error, Page, Playwright
-
-
-async def test_should_use_data_test_id_in_strict_errors(page: Page, playwright: Playwright) -> None:
- playwright.selectors.set_test_id_attribute("data-custom-id")
- try:
- await page.set_content(
- """
-
-
- """
- )
- with pytest.raises(Error) as exc_info:
- await page.locator(".foo").hover(timeout=200)
- assert "strict mode violation" in exc_info.value.message
- assert ' None:
- await page.set_content(
- """
-
Hello my
-wo"rld """
- )
- await page.eval_on_selector(
- "input",
- """input => {
- input.setAttribute('placeholder', 'hello my\\nwo"rld');
- input.setAttribute('title', 'hello my\\nwo"rld');
- input.setAttribute('alt', 'hello my\\nwo"rld');
- }""",
- )
- await expect(page.get_by_text('hello my\nwo"rld')).to_have_attribute("id", "label")
- await expect(page.get_by_text('hello my wo"rld')).to_have_attribute("id", "label")
- await expect(page.get_by_label('hello my\nwo"rld')).to_have_attribute("id", "control")
- await expect(page.get_by_placeholder('hello my\nwo"rld')).to_have_attribute("id", "control")
- await expect(page.get_by_alt_text('hello my\nwo"rld')).to_have_attribute("id", "control")
- await expect(page.get_by_title('hello my\nwo"rld')).to_have_attribute("id", "control")
-
- await page.set_content(
- """
-
Hello my
-world """
- )
- await page.eval_on_selector(
- "input",
- """input => {
- input.setAttribute('placeholder', 'hello my\\nworld');
- input.setAttribute('title', 'hello my\\nworld');
- input.setAttribute('alt', 'hello my\\nworld');
- }""",
- )
- await expect(page.get_by_text("hello my\nworld")).to_have_attribute("id", "label")
- await expect(page.get_by_text("hello my world")).to_have_attribute("id", "label")
- await expect(page.get_by_label("hello my\nworld")).to_have_attribute("id", "control")
- await expect(page.get_by_placeholder("hello my\nworld")).to_have_attribute("id", "control")
- await expect(page.get_by_alt_text("hello my\nworld")).to_have_attribute("id", "control")
- await expect(page.get_by_title("hello my\nworld")).to_have_attribute("id", "control")
-
- await page.set_content("""
Text here
""")
- await expect(page.get_by_title("my title", exact=True)).to_have_count(1, timeout=500)
- await expect(page.get_by_title("my t\\itle", exact=True)).to_have_count(0, timeout=500)
- await expect(page.get_by_title("my t\\\\itle", exact=True)).to_have_count(0, timeout=500)
-
- await page.set_content("""
foo >> bar """)
- await page.eval_on_selector(
- "input",
- """input => {
- input.setAttribute('placeholder', 'foo >> bar');
- input.setAttribute('title', 'foo >> bar');
- input.setAttribute('alt', 'foo >> bar');
- }""",
- )
- assert await page.get_by_text("foo >> bar").text_content() == "foo >> bar"
- await expect(page.locator("label")).to_have_text("foo >> bar")
- await expect(page.get_by_text("foo >> bar")).to_have_text("foo >> bar")
- assert await page.get_by_text(re.compile("foo >> bar")).text_content() == "foo >> bar"
- await expect(page.get_by_label("foo >> bar")).to_have_attribute("id", "target")
- await expect(page.get_by_label(re.compile("foo >> bar"))).to_have_attribute("id", "target")
- await expect(page.get_by_placeholder("foo >> bar")).to_have_attribute("id", "target")
- await expect(page.get_by_alt_text("foo >> bar")).to_have_attribute("id", "target")
- await expect(page.get_by_title("foo >> bar")).to_have_attribute("id", "target")
- await expect(page.get_by_placeholder(re.compile("foo >> bar"))).to_have_attribute(
- "id", "target"
- )
- await expect(page.get_by_alt_text(re.compile("foo >> bar"))).to_have_attribute("id", "target")
- await expect(page.get_by_title(re.compile("foo >> bar"))).to_have_attribute("id", "target")
-
-
-async def test_get_by_role_escaping(
- page: Page,
-) -> None:
- await page.set_content(
- """
-
issues 123
-
he llo 56
-
Click me
- """
- )
- assert await page.get_by_role("button").evaluate_all("els => els.map(e => e.outerHTML)") == [
- "
Click me ",
- ]
- assert await page.get_by_role("link").evaluate_all("els => els.map(e => e.outerHTML)") == [
- """
issues 123 """,
- """
he llo 56 """,
- ]
-
- assert await page.get_by_role("link", name="issues 123").evaluate_all(
- "els => els.map(e => e.outerHTML)"
- ) == [
- """
issues 123 """,
- ]
- assert await page.get_by_role("link", name="sues").evaluate_all(
- "els => els.map(e => e.outerHTML)"
- ) == [
- """
issues 123 """,
- ]
- assert await page.get_by_role("link", name=" he \n llo ").evaluate_all(
- "els => els.map(e => e.outerHTML)"
- ) == [
- """
he llo 56 """,
- ]
- assert (
- await page.get_by_role("button", name="issues").evaluate_all(
- "els => els.map(e => e.outerHTML)"
- )
- == []
- )
-
- assert (
- await page.get_by_role("link", name="sues", exact=True).evaluate_all(
- "els => els.map(e => e.outerHTML)"
- )
- == []
- )
- assert await page.get_by_role("link", name=" he \n llo 56 ", exact=True).evaluate_all(
- "els => els.map(e => e.outerHTML)"
- ) == [
- """
he llo 56 """,
- ]
-
- assert await page.get_by_role("button", name="Click me", exact=True).evaluate_all(
- "els => els.map(e => e.outerHTML)"
- ) == [
- "
Click me ",
- ]
- assert (
- await page.get_by_role("button", name="Click \\me", exact=True).evaluate_all(
- "els => els.map(e => e.outerHTML)"
- )
- == []
- )
- assert (
- await page.get_by_role("button", name="Click \\\\me", exact=True).evaluate_all(
- "els => els.map(e => e.outerHTML)"
- )
- == []
- )
-
-
-async def test_include_hidden_should_work(
- page: Page,
-) -> None:
- await page.set_content("""
Hidden """)
- assert (
- await page.get_by_role("button", name="Hidden").evaluate_all(
- "els => els.map(e => e.outerHTML)"
- )
- == []
- )
- assert await page.get_by_role("button", name="Hidden", include_hidden=True).evaluate_all(
- "els => els.map(e => e.outerHTML)"
- ) == [
- """
Hidden """,
- ]
diff --git a/tests/async/test_selectors_misc.py b/tests/async/test_selectors_misc.py
deleted file mode 100644
index 5527d6e..0000000
--- a/tests/async/test_selectors_misc.py
+++ /dev/null
@@ -1,54 +0,0 @@
-# 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.
-
-from playwright.async_api import Page
-
-
-async def test_should_work_with_internal_and(page: Page) -> None:
- await page.set_content(
- """
-
hello
world
-
hello2 world2
- """
- )
- assert (
- await page.eval_on_selector_all(
- 'div >> internal:and="span"', "els => els.map(e => e.textContent)"
- )
- ) == []
- assert (
- await page.eval_on_selector_all(
- 'div >> internal:and=".foo"', "els => els.map(e => e.textContent)"
- )
- ) == ["hello"]
- assert (
- await page.eval_on_selector_all(
- 'div >> internal:and=".bar"', "els => els.map(e => e.textContent)"
- )
- ) == ["world"]
- assert (
- await page.eval_on_selector_all(
- 'span >> internal:and="span"', "els => els.map(e => e.textContent)"
- )
- ) == ["hello2", "world2"]
- assert (
- await page.eval_on_selector_all(
- '.foo >> internal:and="div"', "els => els.map(e => e.textContent)"
- )
- ) == ["hello"]
- assert (
- await page.eval_on_selector_all(
- '.bar >> internal:and="span"', "els => els.map(e => e.textContent)"
- )
- ) == ["world2"]
diff --git a/tests/async/test_selectors_text.py b/tests/async/test_selectors_text.py
deleted file mode 100644
index 5602928..0000000
--- a/tests/async/test_selectors_text.py
+++ /dev/null
@@ -1,210 +0,0 @@
-# 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 re
-
-import pytest
-
-from playwright.async_api import Error, Page, expect
-
-
-async def test_has_text_and_internal_text_should_match_full_node_text_in_strict_mode(
- page: Page,
-) -> None:
- await page.set_content(
- """
-
helloworld
-
hello
- """
- )
- await expect(page.get_by_text("helloworld", exact=True)).to_have_id("div1")
- await expect(page.get_by_text("hello", exact=True)).to_have_id("div2")
- await expect(page.locator("div", has_text=re.compile("^helloworld$"))).to_have_id("div1")
- await expect(page.locator("div", has_text=re.compile("^hello$"))).to_have_id("div2")
-
- await page.set_content(
- """
-
hello world
-
hello
- """
- )
- await expect(page.get_by_text("helloworld", exact=True)).to_have_id("div1")
- assert await page.get_by_text("hello", exact=True).evaluate_all(
- "els => els.map(e => e.id)"
- ) == ["span1", "span2"]
- await expect(page.locator("div", has_text=re.compile("^helloworld$"))).to_have_id("div1")
- await expect(page.locator("div", has_text=re.compile("^hello$"))).to_have_id("div2")
-
-
-async def test_should_work(page: Page) -> None:
- await page.set_content(
- """
-
yo
ya
\nye
- """
- )
- assert await page.eval_on_selector("text=ya", "e => e.outerHTML") == "
ya
"
- assert await page.eval_on_selector('text="ya"', "e => e.outerHTML") == "
ya
"
- assert await page.eval_on_selector("text=/^[ay]+$/", "e => e.outerHTML") == "
ya
"
- assert await page.eval_on_selector("text=/Ya/i", "e => e.outerHTML") == "
ya
"
- assert await page.eval_on_selector("text=ye", "e => e.outerHTML") == "
\nye
"
- assert ">\nye
" in await page.get_by_text("ye").evaluate("e => e.outerHTML")
-
- await page.set_content(
- """
- ye
ye
- """
- )
- assert await page.eval_on_selector('text="ye"', "e => e.outerHTML") == " ye
"
- assert "> ye " in await page.get_by_text("ye", exact=True).first.evaluate(
- "e => e.outerHTML"
- )
-
- await page.set_content(
- """
- yo
"ya
hello world!
- """
- )
- assert await page.eval_on_selector('text="\\"ya"', "e => e.outerHTML") == '"ya
'
- assert (
- await page.eval_on_selector("text=/hello/", "e => e.outerHTML")
- == " hello world!
"
- )
- assert (
- await page.eval_on_selector("text=/^\\s*heLLo/i", "e => e.outerHTML")
- == " hello world!
"
- )
-
- await page.set_content(
- """
-
- """
- )
- assert await page.eval_on_selector("text=hey", "e => e.outerHTML") == "hey
"
- assert await page.eval_on_selector('text=yo>>text="ya"', "e => e.outerHTML") == "ya
"
- assert await page.eval_on_selector('text=yo>> text="ya"', "e => e.outerHTML") == "ya
"
- assert await page.eval_on_selector("text=yo >>text='ya'", "e => e.outerHTML") == "ya
"
- assert (
- await page.eval_on_selector("text=yo >> text='ya'", "e => e.outerHTML") == "ya
"
- )
- assert await page.eval_on_selector("'yo'>>\"ya\"", "e => e.outerHTML") == "ya
"
- assert await page.eval_on_selector("\"yo\" >> 'ya'", "e => e.outerHTML") == "ya
"
-
- await page.set_content(
- """
- yo
yo
- """
- )
- assert (
- await page.eval_on_selector_all("text=yo", "es => es.map(e => e.outerHTML).join('\\n')")
- == 'yo
\nyo
'
- )
-
- await page.set_content("'
\"
\\
x
")
- assert await page.eval_on_selector("text='\\''", "e => e.outerHTML") == "'
"
- assert await page.eval_on_selector("text='\"'", "e => e.outerHTML") == '"
'
- assert await page.eval_on_selector('text="\\""', "e => e.outerHTML") == '"
'
- assert await page.eval_on_selector('text="\'"', "e => e.outerHTML") == "'
"
- assert await page.eval_on_selector('text="\\x"', "e => e.outerHTML") == "x
"
- assert await page.eval_on_selector("text='\\x'", "e => e.outerHTML") == "x
"
- assert await page.eval_on_selector("text='\\\\'", "e => e.outerHTML") == "\\
"
- assert await page.eval_on_selector('text="\\\\"', "e => e.outerHTML") == "\\
"
- assert await page.eval_on_selector('text="', "e => e.outerHTML") == '"
'
- assert await page.eval_on_selector("text='", "e => e.outerHTML") == "'
"
- assert await page.eval_on_selector('"x"', "e => e.outerHTML") == "x
"
- assert await page.eval_on_selector("'x'", "e => e.outerHTML") == "x
"
- with pytest.raises(Error):
- await page.query_selector_all('"')
- with pytest.raises(Error):
- await page.query_selector_all("'")
-
- await page.set_content(" '
\"
")
- assert await page.eval_on_selector('text="', "e => e.outerHTML") == ' "
'
- assert await page.eval_on_selector("text='", "e => e.outerHTML") == " '
"
-
- await page.set_content("Hi''>>foo=bar
")
- assert (
- await page.eval_on_selector("text=\"Hi''>>foo=bar\"", "e => e.outerHTML")
- == "Hi''>>foo=bar
"
- )
- await page.set_content("Hi'\">>foo=bar
")
- assert (
- await page.eval_on_selector('text="Hi\'\\">>foo=bar"', "e => e.outerHTML")
- == "Hi'\">>foo=bar
"
- )
-
- await page.set_content("Hi>>
")
- assert await page.eval_on_selector('text="Hi>>">>span', "e => e.outerHTML") == " "
- assert (
- await page.eval_on_selector("text=/Hi\\>\\>/ >> span", "e => e.outerHTML")
- == " "
- )
-
- await page.set_content("a b
a
")
- assert await page.eval_on_selector("text=a", "e => e.outerHTML") == "a b
"
- assert await page.eval_on_selector("text=b", "e => e.outerHTML") == "a b
"
- assert await page.eval_on_selector("text=ab", "e => e.outerHTML") == "a b
"
- assert await page.query_selector("text=abc") is None
- assert await page.eval_on_selector_all("text=a", "els => els.length") == 2
- assert await page.eval_on_selector_all("text=b", "els => els.length") == 1
- assert await page.eval_on_selector_all("text=ab", "els => els.length") == 1
- assert await page.eval_on_selector_all("text=abc", "els => els.length") == 0
-
- await page.set_content("
")
- await page.eval_on_selector(
- "div",
- """div => {
- div.appendChild(document.createTextNode('hello'))
- div.appendChild(document.createTextNode('world'))
- }""",
- )
- await page.eval_on_selector(
- "span",
- """span => {
- span.appendChild(document.createTextNode('hello'))
- span.appendChild(document.createTextNode('world'))
- }""",
- )
- assert await page.eval_on_selector("text=lowo", "e => e.outerHTML") == "helloworld
"
- assert (
- await page.eval_on_selector_all("text=lowo", "els => els.map(e => e.outerHTML).join('')")
- == "helloworld
helloworld "
- )
-
- await page.set_content("Sign in Hello\n \nworld ")
- assert (
- await page.eval_on_selector("text=Sign in", "e => e.outerHTML")
- == "Sign in "
- )
- assert len((await page.query_selector_all("text=Sign \tin"))) == 1
- assert len((await page.query_selector_all('text="Sign in"'))) == 1
- assert (
- await page.eval_on_selector("text=lo wo", "e => e.outerHTML")
- == "Hello\n \nworld "
- )
- assert (
- await page.eval_on_selector('text="Hello world"', "e => e.outerHTML")
- == "Hello\n \nworld "
- )
- assert await page.query_selector('text="lo wo"') is None
- assert len((await page.query_selector_all("text=lo \nwo"))) == 1
- assert len(await page.query_selector_all('text="lo \nwo"')) == 0
-
- await page.set_content("let'shello
")
- assert (
- await page.eval_on_selector("text=/let's/i >> span", "e => e.outerHTML")
- == "hello "
- )
- assert (
- await page.eval_on_selector("text=/let\\'s/i >> span", "e => e.outerHTML")
- == "hello "
- )
diff --git a/tests/async/test_tap.py b/tests/async/test_tap.py
deleted file mode 100644
index abb3c61..0000000
--- a/tests/async/test_tap.py
+++ /dev/null
@@ -1,237 +0,0 @@
-# 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
-from typing import AsyncGenerator, Optional, cast
-
-import pytest
-
-from playwright.async_api import Browser, BrowserContext, ElementHandle, JSHandle, Page
-
-
-@pytest.fixture
-async def context(browser: Browser) -> AsyncGenerator[BrowserContext, None]:
- context = await browser.new_context(has_touch=True)
- yield context
- await context.close()
-
-
-async def test_should_send_all_of_the_correct_events(page: Page) -> None:
- await page.set_content(
- """
- a
- b
- """
- )
- await page.tap("#a")
- element_handle = await track_events(await page.query_selector("#b"))
- await page.tap("#b")
- assert await element_handle.json_value() == [
- "pointerover",
- "pointerenter",
- "pointerdown",
- "touchstart",
- "pointerup",
- "pointerout",
- "pointerleave",
- "touchend",
- "mouseover",
- "mouseenter",
- "mousemove",
- "mousedown",
- "mouseup",
- "click",
- ]
-
-
-async def test_should_not_send_mouse_events_touchstart_is_canceled(page: Page) -> None:
- await page.set_content("hello world")
- await page.evaluate(
- """() => {
- // touchstart is not cancelable unless passive is false
- document.addEventListener('touchstart', t => t.preventDefault(), {passive: false});
- }"""
- )
- events_handle = await track_events(await page.query_selector("body"))
- await page.tap("body")
- assert await events_handle.json_value() == [
- "pointerover",
- "pointerenter",
- "pointerdown",
- "touchstart",
- "pointerup",
- "pointerout",
- "pointerleave",
- "touchend",
- ]
-
-
-async def test_should_not_send_mouse_events_touchend_is_canceled(page: Page) -> None:
- await page.set_content("hello world")
- await page.evaluate(
- """() => {
- // touchstart is not cancelable unless passive is false
- document.addEventListener('touchend', t => t.preventDefault());
- }"""
- )
- events_handle = await track_events(await page.query_selector("body"))
- await page.tap("body")
- assert await events_handle.json_value() == [
- "pointerover",
- "pointerenter",
- "pointerdown",
- "touchstart",
- "pointerup",
- "pointerout",
- "pointerleave",
- "touchend",
- ]
-
-
-async def test_should_work_with_modifiers(page: Page) -> None:
- await page.set_content("hello world")
- alt_key_promise = asyncio.create_task(
- page.evaluate(
- """() => new Promise(resolve => {
- document.addEventListener('touchstart', event => {
- resolve(event.altKey);
- }, {passive: false});
- })"""
- )
- )
- await asyncio.sleep(0) # make sure the evals hit the page
- await page.evaluate("""() => void 0""")
- await page.tap("body", modifiers=["Alt"])
- assert await alt_key_promise is True
-
-
-async def test_should_send_well_formed_touch_points(page: Page) -> None:
- promises = asyncio.gather(
- page.evaluate(
- """() => new Promise(resolve => {
- document.addEventListener('touchstart', event => {
- resolve([...event.touches].map(t => ({
- identifier: t.identifier,
- clientX: t.clientX,
- clientY: t.clientY,
- pageX: t.pageX,
- pageY: t.pageY,
- radiusX: 'radiusX' in t ? t.radiusX : t['webkitRadiusX'],
- radiusY: 'radiusY' in t ? t.radiusY : t['webkitRadiusY'],
- rotationAngle: 'rotationAngle' in t ? t.rotationAngle : t['webkitRotationAngle'],
- force: 'force' in t ? t.force : t['webkitForce'],
- })));
- }, false);
- })"""
- ),
- page.evaluate(
- """() => new Promise(resolve => {
- document.addEventListener('touchend', event => {
- resolve([...event.touches].map(t => ({
- identifier: t.identifier,
- clientX: t.clientX,
- clientY: t.clientY,
- pageX: t.pageX,
- pageY: t.pageY,
- radiusX: 'radiusX' in t ? t.radiusX : t['webkitRadiusX'],
- radiusY: 'radiusY' in t ? t.radiusY : t['webkitRadiusY'],
- rotationAngle: 'rotationAngle' in t ? t.rotationAngle : t['webkitRotationAngle'],
- force: 'force' in t ? t.force : t['webkitForce'],
- })));
- }, false);
- })"""
- ),
- )
- # make sure the evals hit the page
- await page.evaluate("""() => void 0""")
- await page.touchscreen.tap(40, 60)
- [touchstart, touchend] = await promises
- assert touchstart == [
- {
- "clientX": 40,
- "clientY": 60,
- "force": 1,
- "identifier": 0,
- "pageX": 40,
- "pageY": 60,
- "radiusX": 1,
- "radiusY": 1,
- "rotationAngle": 0,
- }
- ]
- assert touchend == []
-
-
-async def test_should_wait_until_an_element_is_visible_to_tap_it(page: Page) -> None:
- div = cast(
- ElementHandle,
- await page.evaluate_handle(
- """() => {
- const button = document.createElement('button');
- button.textContent = 'not clicked';
- document.body.appendChild(button);
- button.style.display = 'none';
- return button;
- }"""
- ),
- )
- tap_promise = asyncio.create_task(div.tap())
- await asyncio.sleep(0) # issue tap
- await div.evaluate("""div => div.onclick = () => div.textContent = 'clicked'""")
- await div.evaluate("""div => div.style.display = 'block'""")
- await tap_promise
- assert await div.text_content() == "clicked"
-
-
-async def test_locators_tap(page: Page) -> None:
- await page.set_content(
- """
- a
- b
- """
- )
- await page.locator("#a").tap()
- element_handle = await track_events(await page.query_selector("#b"))
- await page.locator("#b").tap()
- assert await element_handle.json_value() == [
- "pointerover",
- "pointerenter",
- "pointerdown",
- "touchstart",
- "pointerup",
- "pointerout",
- "pointerleave",
- "touchend",
- "mouseover",
- "mouseenter",
- "mousemove",
- "mousedown",
- "mouseup",
- "click",
- ]
-
-
-async def track_events(target: Optional[ElementHandle]) -> JSHandle:
- assert target
- return await target.evaluate_handle(
- """target => {
- const events = [];
- for (const event of [
- 'mousedown', 'mouseenter', 'mouseleave', 'mousemove', 'mouseout', 'mouseover', 'mouseup', 'click',
- 'pointercancel', 'pointerdown', 'pointerenter', 'pointerleave', 'pointermove', 'pointerout', 'pointerover', 'pointerup',
- 'touchstart', 'touchend', 'touchmove', 'touchcancel',])
- target.addEventListener(event, () => events.push(event), false);
- return events;
- }"""
- )
diff --git a/tests/async/test_tracing.py b/tests/async/test_tracing.py
deleted file mode 100644
index a9cfdfb..0000000
--- a/tests/async/test_tracing.py
+++ /dev/null
@@ -1,285 +0,0 @@
-# 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 re
-from pathlib import Path
-from typing import Dict, List
-
-from playwright.async_api import Browser, BrowserContext, BrowserType, Page
-from tests.server import Server
-from tests.utils import get_trace_actions, parse_trace
-
-
-async def test_browser_context_output_trace(
- browser: Browser, server: Server, tmp_path: Path
-) -> None:
- context = await browser.new_context()
- await context.tracing.start(screenshots=True, snapshots=True)
- page = await context.new_page()
- await page.goto(server.PREFIX + "/grid.html")
- await context.tracing.stop(path=tmp_path / "trace.zip")
- assert Path(tmp_path / "trace.zip").exists()
-
-
-async def test_start_stop(browser: Browser) -> None:
- context = await browser.new_context()
- await context.tracing.start()
- await context.tracing.stop()
- await context.close()
-
-
-async def test_browser_context_should_not_throw_when_stopping_without_start_but_not_exporting(
- context: BrowserContext, server: Server, tmp_path: Path
-) -> None:
- await context.tracing.stop()
-
-
-async def test_browser_context_output_trace_chunk(
- browser: Browser, server: Server, tmp_path: Path
-) -> None:
- context = await browser.new_context()
- await context.tracing.start(screenshots=True, snapshots=True)
- page = await context.new_page()
- await page.goto(server.PREFIX + "/grid.html")
- button = page.locator(".box").first
-
- await context.tracing.start_chunk(title="foo")
- await button.click()
- await context.tracing.stop_chunk(path=tmp_path / "trace1.zip")
- assert Path(tmp_path / "trace1.zip").exists()
-
- await context.tracing.start_chunk(title="foo")
- await button.click()
- await context.tracing.stop_chunk(path=tmp_path / "trace2.zip")
- assert Path(tmp_path / "trace2.zip").exists()
-
-
-async def test_should_collect_sources(
- context: BrowserContext, page: Page, server: Server, tmp_path: Path
-) -> None:
- await context.tracing.start(sources=True)
- await page.goto(server.EMPTY_PAGE)
- await page.set_content("Click ")
- await page.click("button")
- path = tmp_path / "trace.zip"
- await context.tracing.stop(path=path)
-
- (resources, events) = parse_trace(path)
- current_file_content = Path(__file__).read_bytes()
- found_current_file = False
- for name, resource in resources.items():
- if resource == current_file_content:
- found_current_file = True
- break
- assert found_current_file
-
-
-async def test_should_collect_trace_with_resources_but_no_js(
- context: BrowserContext, page: Page, server: Server, tmpdir: Path
-) -> None:
- await context.tracing.start(screenshots=True, snapshots=True)
- await page.goto(server.PREFIX + "/frames/frame.html")
- await page.set_content("Click ")
- await page.click('"Click"')
- await page.mouse.move(20, 20)
- await page.mouse.dblclick(30, 30)
- await page.keyboard.insert_text("abc")
- await page.wait_for_timeout(2000) # Give it some time to produce screenshots.
- await page.route(
- "**/empty.html", lambda route: route.continue_()
- ) # should produce a route.continue_ entry.
- await page.goto(server.EMPTY_PAGE)
- await page.goto(
- server.PREFIX + "/one-style.html"
- ) # should not produce a route.continue_ entry since we continue all routes if no match.
- await page.close()
- trace_file_path = tmpdir / "trace.zip"
- await context.tracing.stop(path=trace_file_path)
-
- (_, events) = parse_trace(trace_file_path)
- assert events[0]["type"] == "context-options"
- assert get_trace_actions(events) == [
- "Page.goto",
- "Page.set_content",
- "Page.click",
- "Mouse.move",
- "Mouse.dblclick",
- "Keyboard.insert_text",
- "Page.wait_for_timeout",
- "Page.route",
- "Page.goto",
- "Route.continue_",
- "Page.goto",
- "Page.close",
- ]
-
- assert len(list(filter(lambda e: e["type"] == "frame-snapshot", events))) >= 1
- assert len(list(filter(lambda e: e["type"] == "screencast-frame", events))) >= 1
- style = list(
- filter(
- lambda e: e["type"] == "resource-snapshot"
- and e["snapshot"]["request"]["url"].endswith("style.css"),
- events,
- )
- )[0]
- assert style
- assert style["snapshot"]["response"]["content"]["_sha1"]
- script = list(
- filter(
- lambda e: e["type"] == "resource-snapshot"
- and e["snapshot"]["request"]["url"].endswith("script.js"),
- events,
- )
- )[0]
- assert script
- assert script["snapshot"]["response"]["content"].get("_sha1") is None
-
-
-async def test_should_collect_two_traces(
- context: BrowserContext, page: Page, server: Server, tmpdir: Path
-) -> None:
- await context.tracing.start(screenshots=True, snapshots=True)
- await page.goto(server.EMPTY_PAGE)
- await page.set_content("Click ")
- await page.click('"Click"')
- tracing1_path = tmpdir / "trace1.zip"
- await context.tracing.stop(path=tracing1_path)
-
- await context.tracing.start(screenshots=True, snapshots=True)
- await page.dblclick('"Click"')
- await page.close()
- tracing2_path = tmpdir / "trace2.zip"
- await context.tracing.stop(path=tracing2_path)
-
- (_, events) = parse_trace(tracing1_path)
- assert events[0]["type"] == "context-options"
- assert get_trace_actions(events) == [
- "Page.goto",
- "Page.set_content",
- "Page.click",
- ]
-
- (_, events) = parse_trace(tracing2_path)
- assert events[0]["type"] == "context-options"
- assert get_trace_actions(events) == ["Page.dblclick", "Page.close"]
-
-
-async def test_should_not_throw_when_stopping_without_start_but_not_exporting(
- context: BrowserContext,
-) -> None:
- await context.tracing.stop()
-
-
-async def test_should_work_with_playwright_context_managers(
- context: BrowserContext, page: Page, server: Server, tmpdir: Path
-) -> None:
- await context.tracing.start(screenshots=True, snapshots=True)
- await page.goto(server.EMPTY_PAGE)
- await page.set_content("Click ")
- async with page.expect_console_message() as message_info:
- await page.evaluate('() => console.log("hello")')
- await page.click('"Click"')
- assert (await message_info.value).text == "hello"
-
- async with page.expect_popup():
- await page.evaluate("window._popup = window.open(document.location.href)")
- trace_file_path = tmpdir / "trace.zip"
- await context.tracing.stop(path=trace_file_path)
-
- (_, events) = parse_trace(trace_file_path)
- assert events[0]["type"] == "context-options"
- assert get_trace_actions(events) == [
- "Page.goto",
- "Page.set_content",
- "Page.expect_console_message",
- "Page.evaluate",
- "Page.click",
- "Page.expect_popup",
- "Page.evaluate",
- ]
-
-
-async def test_should_display_wait_for_load_state_even_if_did_not_wait_for_it(
- context: BrowserContext, page: Page, server: Server, tmpdir: Path
-) -> None:
- await context.tracing.start(screenshots=True, snapshots=True)
-
- await page.goto(server.EMPTY_PAGE)
- await page.wait_for_load_state("load")
- await page.wait_for_load_state("load")
-
- trace_file_path = tmpdir / "trace.zip"
- await context.tracing.stop(path=trace_file_path)
-
- (_, events) = parse_trace(trace_file_path)
- assert get_trace_actions(events) == [
- "Page.goto",
- "Page.wait_for_load_state",
- "Page.wait_for_load_state",
- ]
-
-
-async def test_should_respect_traces_dir_and_name(
- browser_type: BrowserType,
- server: Server,
- tmpdir: Path,
- launch_arguments: Dict,
-) -> None:
- traces_dir = tmpdir / "traces"
- browser = await browser_type.launch(traces_dir=traces_dir, **launch_arguments)
- context = await browser.new_context()
- page = await context.new_page()
-
- await context.tracing.start(name="name1", snapshots=True)
- await page.goto(server.PREFIX + "/one-style.html")
- await context.tracing.stop_chunk(path=tmpdir / "trace1.zip")
- assert (traces_dir / "name1.trace").exists()
- assert (traces_dir / "name1.network").exists()
-
- await context.tracing.start_chunk(name="name2")
- await page.goto(server.PREFIX + "/har.html")
- await context.tracing.stop(path=tmpdir / "trace2.zip")
- assert (traces_dir / "name2.trace").exists()
- assert (traces_dir / "name2.network").exists()
-
- await browser.close()
-
- def resource_names(resources: Dict[str, bytes]) -> List[str]:
- return sorted(
- [
- re.sub(r"^resources/.*\.(html|css)$", r"resources/XXX.\g<1>", file)
- for file in resources.keys()
- ]
- )
-
- (resources, events) = parse_trace(tmpdir / "trace1.zip")
- assert get_trace_actions(events) == ["Page.goto"]
- assert resource_names(resources) == [
- "resources/XXX.css",
- "resources/XXX.html",
- "trace.network",
- "trace.stacks",
- "trace.trace",
- ]
-
- (resources, events) = parse_trace(tmpdir / "trace2.zip")
- assert get_trace_actions(events) == ["Page.goto"]
- assert resource_names(resources) == [
- "resources/XXX.css",
- "resources/XXX.html",
- "resources/XXX.html",
- "trace.network",
- "trace.stacks",
- "trace.trace",
- ]
diff --git a/tests/async/test_unroute_behavior.py b/tests/async/test_unroute_behavior.py
deleted file mode 100644
index 036423c..0000000
--- a/tests/async/test_unroute_behavior.py
+++ /dev/null
@@ -1,453 +0,0 @@
-# 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 re
-
-from playwright.async_api import BrowserContext, Error, Page, Route
-from tests.server import Server
-from tests.utils import must
-
-
-async def test_context_unroute_should_not_wait_for_pending_handlers_to_complete(
- page: Page, context: BrowserContext, server: Server
-) -> None:
- second_handler_called = False
-
- async def _handler1(route: Route) -> None:
- nonlocal second_handler_called
- second_handler_called = True
- await route.continue_()
-
- await context.route(
- re.compile(".*"),
- _handler1,
- )
- route_future: "asyncio.Future[Route]" = asyncio.Future()
- route_barrier_future: "asyncio.Future[None]" = asyncio.Future()
-
- async def _handler2(route: Route) -> None:
- route_future.set_result(route)
- await route_barrier_future
- await route.fallback()
-
- await context.route(
- re.compile(".*"),
- _handler2,
- )
- navigation_task = asyncio.create_task(page.goto(server.EMPTY_PAGE))
- await route_future
- await context.unroute(
- re.compile(".*"),
- _handler2,
- )
- route_barrier_future.set_result(None)
- await navigation_task
- assert second_handler_called
-
-
-async def test_context_unroute_all_removes_all_handlers(
- page: Page, context: BrowserContext, server: Server
-) -> None:
- await context.route(
- "**/*",
- lambda route: route.abort(),
- )
- await context.route(
- "**/empty.html",
- lambda route: route.abort(),
- )
- await context.unroute_all()
- await page.goto(server.EMPTY_PAGE)
-
-
-async def test_context_unroute_all_should_not_wait_for_pending_handlers_to_complete(
- page: Page, context: BrowserContext, server: Server
-) -> None:
- second_handler_called = False
-
- async def _handler1(route: Route) -> None:
- nonlocal second_handler_called
- second_handler_called = True
- await route.abort()
-
- await context.route(
- re.compile(".*"),
- _handler1,
- )
- route_future: "asyncio.Future[Route]" = asyncio.Future()
- route_barrier_future: "asyncio.Future[None]" = asyncio.Future()
-
- async def _handler2(route: Route) -> None:
- route_future.set_result(route)
- await route_barrier_future
- await route.fallback()
-
- await context.route(
- re.compile(".*"),
- _handler2,
- )
- navigation_task = asyncio.create_task(page.goto(server.EMPTY_PAGE))
- await route_future
- did_unroute = False
-
- async def _unroute_promise() -> None:
- nonlocal did_unroute
- await context.unroute_all(behavior="wait")
- did_unroute = True
-
- unroute_task = asyncio.create_task(_unroute_promise())
- await asyncio.sleep(0.5)
- assert did_unroute is False
- route_barrier_future.set_result(None)
- await unroute_task
- assert did_unroute
- await navigation_task
- assert second_handler_called is False
-
-
-async def test_context_unroute_all_should_not_wait_for_pending_handlers_to_complete_if_behavior_is_ignore_errors(
- page: Page, context: BrowserContext, server: Server
-) -> None:
- second_handler_called = False
-
- async def _handler1(route: Route) -> None:
- nonlocal second_handler_called
- second_handler_called = True
- await route.abort()
-
- await context.route(
- re.compile(".*"),
- _handler1,
- )
- route_future: "asyncio.Future[Route]" = asyncio.Future()
- route_barrier_future: "asyncio.Future[None]" = asyncio.Future()
-
- async def _handler2(route: Route) -> None:
- route_future.set_result(route)
- await route_barrier_future
- raise Exception("Handler error")
-
- await context.route(
- re.compile(".*"),
- _handler2,
- )
- navigation_task = asyncio.create_task(page.goto(server.EMPTY_PAGE))
- await route_future
- did_unroute = False
-
- async def _unroute_promise() -> None:
- await context.unroute_all(behavior="ignoreErrors")
- nonlocal did_unroute
- did_unroute = True
-
- unroute_task = asyncio.create_task(_unroute_promise())
- await asyncio.sleep(0.5)
- await unroute_task
- assert did_unroute
- route_barrier_future.set_result(None)
- try:
- await navigation_task
- except Error:
- pass
- # The error in the unrouted handler should be silently caught and remaining handler called.
- assert not second_handler_called
-
-
-async def test_page_close_should_not_wait_for_active_route_handlers_on_the_owning_context(
- page: Page, context: BrowserContext, server: Server
-) -> None:
- route_future: "asyncio.Future[Route]" = asyncio.Future()
- await context.route(
- re.compile(".*"),
- lambda route: route_future.set_result(route),
- )
- await page.route(
- re.compile(".*"),
- lambda route: route.fallback(),
- )
-
- async def _goto_ignore_exceptions() -> None:
- try:
- await page.goto(server.EMPTY_PAGE)
- except Error:
- pass
-
- asyncio.create_task(_goto_ignore_exceptions())
- await route_future
- await page.close()
-
-
-async def test_context_close_should_not_wait_for_active_route_handlers_on_the_owned_pages(
- page: Page, context: BrowserContext, server: Server
-) -> None:
- route_future: "asyncio.Future[Route]" = asyncio.Future()
- await page.route(
- re.compile(".*"),
- lambda route: route_future.set_result(route),
- )
- await page.route(re.compile(".*"), lambda route: route.fallback())
-
- async def _goto_ignore_exceptions() -> None:
- try:
- await page.goto(server.EMPTY_PAGE)
- except Error:
- pass
-
- asyncio.create_task(_goto_ignore_exceptions())
- await route_future
- await context.close()
-
-
-async def test_page_unroute_should_not_wait_for_pending_handlers_to_complete(
- page: Page, server: Server
-) -> None:
- second_handler_called = False
-
- async def _handler1(route: Route) -> None:
- nonlocal second_handler_called
- second_handler_called = True
- await route.continue_()
-
- await page.route(
- re.compile(".*"),
- _handler1,
- )
- route_future: "asyncio.Future[Route]" = asyncio.Future()
- route_barrier_future: "asyncio.Future[None]" = asyncio.Future()
-
- async def _handler2(route: Route) -> None:
- route_future.set_result(route)
- await route_barrier_future
- await route.fallback()
-
- await page.route(
- re.compile(".*"),
- _handler2,
- )
- navigation_task = asyncio.create_task(page.goto(server.EMPTY_PAGE))
- await route_future
- await page.unroute(
- re.compile(".*"),
- _handler2,
- )
- route_barrier_future.set_result(None)
- await navigation_task
- assert second_handler_called
-
-
-async def test_page_unroute_all_removes_all_routes(page: Page, server: Server) -> None:
- await page.route(
- "**/*",
- lambda route: route.abort(),
- )
- await page.route(
- "**/empty.html",
- lambda route: route.abort(),
- )
- await page.unroute_all()
- response = must(await page.goto(server.EMPTY_PAGE))
- assert response.ok
-
-
-async def test_page_unroute_should_wait_for_pending_handlers_to_complete(
- page: Page, server: Server
-) -> None:
- second_handler_called = False
-
- async def _handler1(route: Route) -> None:
- nonlocal second_handler_called
- second_handler_called = True
- await route.abort()
-
- await page.route(
- "**/*",
- _handler1,
- )
- route_future: "asyncio.Future[Route]" = asyncio.Future()
- route_barrier_future: "asyncio.Future[None]" = asyncio.Future()
-
- async def _handler2(route: Route) -> None:
- route_future.set_result(route)
- await route_barrier_future
- await route.fallback()
-
- await page.route(
- "**/*",
- _handler2,
- )
- navigation_task = asyncio.create_task(page.goto(server.EMPTY_PAGE))
- await route_future
- did_unroute = False
-
- async def _unroute_promise() -> None:
- await page.unroute_all(behavior="wait")
- nonlocal did_unroute
- did_unroute = True
-
- unroute_task = asyncio.create_task(_unroute_promise())
- await asyncio.sleep(0.5)
- assert did_unroute is False
- route_barrier_future.set_result(None)
- await unroute_task
- assert did_unroute
- await navigation_task
- assert second_handler_called is False
-
-
-async def test_page_unroute_all_should_not_wait_for_pending_handlers_to_complete_if_behavior_is_ignore_errors(
- page: Page, server: Server
-) -> None:
- second_handler_called = False
-
- async def _handler1(route: Route) -> None:
- nonlocal second_handler_called
- second_handler_called = True
- await route.abort()
-
- await page.route(re.compile(".*"), _handler1)
- route_future: "asyncio.Future[Route]" = asyncio.Future()
- route_barrier_future: "asyncio.Future[None]" = asyncio.Future()
-
- async def _handler2(route: Route) -> None:
- route_future.set_result(route)
- await route_barrier_future
- raise Exception("Handler error")
-
- await page.route(re.compile(".*"), _handler2)
- navigation_task = asyncio.create_task(page.goto(server.EMPTY_PAGE))
- await route_future
- did_unroute = False
-
- async def _unroute_promise() -> None:
- await page.unroute_all(behavior="ignoreErrors")
- nonlocal did_unroute
- did_unroute = True
-
- unroute_task = asyncio.create_task(_unroute_promise())
- await asyncio.sleep(0.5)
- await unroute_task
- assert did_unroute
- route_barrier_future.set_result(None)
- try:
- await navigation_task
- except Error:
- pass
- # The error in the unrouted handler should be silently caught.
- assert not second_handler_called
-
-
-async def test_page_close_does_not_wait_for_active_route_handlers(
- page: Page, server: Server
-) -> None:
- stalling_future: "asyncio.Future[None]" = asyncio.Future()
- second_handler_called = False
-
- def _handler1(route: Route) -> None:
- nonlocal second_handler_called
- second_handler_called = True
-
- await page.route(
- "**/*",
- _handler1,
- )
- route_future: "asyncio.Future[Route]" = asyncio.Future()
-
- async def _handler2(route: Route) -> None:
- route_future.set_result(route)
- await stalling_future
-
- await page.route(
- "**/*",
- _handler2,
- )
-
- async def _goto_ignore_exceptions() -> None:
- try:
- await page.goto(server.EMPTY_PAGE)
- except Error:
- pass
-
- asyncio.create_task(_goto_ignore_exceptions())
- await route_future
- await page.close()
- await asyncio.sleep(0.5)
- assert not second_handler_called
- stalling_future.cancel()
-
-
-async def test_route_continue_should_not_throw_if_page_has_been_closed(
- page: Page, server: Server
-) -> None:
- route_future: "asyncio.Future[Route]" = asyncio.Future()
- await page.route(
- re.compile(".*"),
- lambda route: route_future.set_result(route),
- )
-
- async def _goto_ignore_exceptions() -> None:
- try:
- await page.goto(server.EMPTY_PAGE)
- except Error:
- pass
-
- asyncio.create_task(_goto_ignore_exceptions())
- route = await route_future
- await page.close()
- # Should not throw.
- await route.continue_()
-
-
-async def test_route_fallback_should_not_throw_if_page_has_been_closed(
- page: Page, server: Server
-) -> None:
- route_future: "asyncio.Future[Route]" = asyncio.Future()
- await page.route(
- re.compile(".*"),
- lambda route: route_future.set_result(route),
- )
-
- async def _goto_ignore_exceptions() -> None:
- try:
- await page.goto(server.EMPTY_PAGE)
- except Error:
- pass
-
- asyncio.create_task(_goto_ignore_exceptions())
- route = await route_future
- await page.close()
- # Should not throw.
- await route.fallback()
-
-
-async def test_route_fulfill_should_not_throw_if_page_has_been_closed(
- page: Page, server: Server
-) -> None:
- route_future: "asyncio.Future[Route]" = asyncio.Future()
- await page.route(
- "**/*",
- lambda route: route_future.set_result(route),
- )
-
- async def _goto_ignore_exceptions() -> None:
- try:
- await page.goto(server.EMPTY_PAGE)
- except Error:
- pass
-
- asyncio.create_task(_goto_ignore_exceptions())
- route = await route_future
- await page.close()
- # Should not throw.
- await route.fulfill()
diff --git a/tests/async/test_video.py b/tests/async/test_video.py
deleted file mode 100644
index 205537c..0000000
--- a/tests/async/test_video.py
+++ /dev/null
@@ -1,82 +0,0 @@
-# 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
-from typing import Dict
-
-from playwright.async_api import Browser, BrowserType
-from tests.server import Server
-
-
-async def test_should_expose_video_path(browser: Browser, tmpdir: Path, server: Server) -> None:
- page = await browser.new_page(record_video_dir=tmpdir)
- await page.goto(server.PREFIX + "/grid.html")
- assert page.video
- path = await page.video.path()
- assert str(tmpdir) in str(path)
- await page.context.close()
-
-
-async def test_short_video_should_throw(browser: Browser, tmpdir: Path, server: Server) -> None:
- page = await browser.new_page(record_video_dir=tmpdir)
- await page.goto(server.PREFIX + "/grid.html")
- assert page.video
- path = await page.video.path()
- assert str(tmpdir) in str(path)
- await page.wait_for_timeout(1000)
- await page.context.close()
- assert os.path.exists(path)
-
-
-async def test_short_video_should_throw_persistent_context(
- browser_type: BrowserType, tmpdir: Path, launch_arguments: Dict, server: Server
-) -> None:
- context = await browser_type.launch_persistent_context(
- str(tmpdir),
- **launch_arguments,
- viewport={"width": 320, "height": 240},
- record_video_dir=str(tmpdir) + "1",
- )
- page = context.pages[0]
- await page.goto(server.PREFIX + "/grid.html")
- await page.wait_for_timeout(1000)
- await context.close()
-
- assert page.video
- path = await page.video.path()
- assert str(tmpdir) in str(path)
-
-
-async def test_should_not_error_if_page_not_closed_before_save_as(
- browser: Browser, tmpdir: Path, server: Server
-) -> None:
- page = await browser.new_page(record_video_dir=tmpdir)
- await page.goto(server.PREFIX + "/grid.html")
- await page.wait_for_timeout(1000) # make sure video has some data
- out_path = tmpdir / "some-video.webm"
- assert page.video
- saved = page.video.save_as(out_path)
- await page.close()
- await saved
- await page.context.close()
- assert os.path.exists(out_path)
-
-
-async def test_should_be_None_if_not_recording(
- browser: Browser, tmpdir: Path, server: Server
-) -> None:
- page = await browser.new_page()
- assert page.video is None
- await page.close()
diff --git a/tests/async/test_wait_for_function.py b/tests/async/test_wait_for_function.py
deleted file mode 100644
index 9d11719..0000000
--- a/tests/async/test_wait_for_function.py
+++ /dev/null
@@ -1,91 +0,0 @@
-# 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.
-
-from datetime import datetime
-
-import pytest
-
-from playwright.async_api import ConsoleMessage, Error, Page
-
-
-async def test_should_timeout(page: Page) -> None:
- start_time = datetime.now()
- timeout = 42
- await page.wait_for_timeout(timeout)
- assert ((datetime.now() - start_time).microseconds * 1000) >= timeout / 2
-
-
-async def test_should_accept_a_string(page: Page) -> None:
- watchdog = page.wait_for_function("window.__FOO === 1")
- await page.evaluate("window['__FOO'] = 1")
- await watchdog
-
-
-async def test_should_work_when_resolved_right_before_execution_context_disposal(
- page: Page,
-) -> None:
- await page.add_init_script("window['__RELOADED'] = true")
- await page.wait_for_function(
- """() => {
- if (!window['__RELOADED'])
- window.location.reload();
- return true;
- }"""
- )
-
-
-async def test_should_poll_on_interval(page: Page) -> None:
- polling = 100
- time_delta = await page.wait_for_function(
- """() => {
- if (!window['__startTime']) {
- window['__startTime'] = Date.now();
- return false;
- }
- return Date.now() - window['__startTime'];
- }""",
- polling=polling,
- )
- assert await time_delta.json_value() >= polling
-
-
-async def test_should_avoid_side_effects_after_timeout(page: Page) -> None:
- counter = 0
-
- async def on_console(message: ConsoleMessage) -> None:
- nonlocal counter
- counter += 1
-
- page.on("console", on_console)
- with pytest.raises(Error) as exc_info:
- await page.wait_for_function(
- """() => {
- window['counter'] = (window['counter'] || 0) + 1;
- console.log(window['counter']);
- }""",
- polling=1,
- timeout=1000,
- )
-
- saved_counter = counter
- await page.wait_for_timeout(2000) # Give it some time to produce more logs.
-
- assert "Timeout 1000ms exceeded" in exc_info.value.message
- assert counter == saved_counter
-
-
-async def test_should_throw_on_polling_mutation(page: Page) -> None:
- with pytest.raises(Error) as exc_info:
- await page.wait_for_function("() => true", polling="mutation") # type: ignore
- assert "Unknown polling option: mutation" in exc_info.value.message
diff --git a/tests/async/test_wait_for_url.py b/tests/async/test_wait_for_url.py
deleted file mode 100644
index b469d79..0000000
--- a/tests/async/test_wait_for_url.py
+++ /dev/null
@@ -1,130 +0,0 @@
-# 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 re
-
-import pytest
-
-from playwright.async_api import Error, Page
-from tests.server import Server
-
-
-async def test_wait_for_url_should_work(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- await page.evaluate("url => window.location.href = url", server.PREFIX + "/grid.html")
- await page.wait_for_url("**/grid.html")
- assert "grid.html" in page.url
-
-
-async def test_wait_for_url_should_respect_timeout(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- with pytest.raises(Error) as exc_info:
- await page.wait_for_url("**/frame.html", timeout=2500)
- assert "Timeout 2500ms exceeded" in exc_info.value.message
-
-
-async def test_wait_for_url_should_work_with_both_domcontentloaded_and_load(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- await page.wait_for_url("**/*", wait_until="domcontentloaded")
- await page.wait_for_url("**/*", wait_until="load")
-
-
-async def test_wait_for_url_should_work_with_clicking_on_anchor_links(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- await page.set_content('foobar ')
- await page.click("a")
- await page.wait_for_url("**/*#foobar")
- assert page.url == server.EMPTY_PAGE + "#foobar"
-
-
-async def test_wait_for_url_should_work_with_history_push_state(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- await page.set_content(
- """
- SPA
-
- """
- )
- await page.click("a")
- await page.wait_for_url("**/wow.html")
- assert page.url == server.PREFIX + "/wow.html"
-
-
-async def test_wait_for_url_should_work_with_history_replace_state(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- await page.set_content(
- """
- SPA
-
- """
- )
- await page.click("a")
- await page.wait_for_url("**/replaced.html")
- assert page.url == server.PREFIX + "/replaced.html"
-
-
-async def test_wait_for_url_should_work_with_dom_history_back_forward(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- await page.set_content(
- """
- back
- forward
-
- """
- )
-
- assert page.url == server.PREFIX + "/second.html"
-
- await page.click("a#back")
- await page.wait_for_url("**/first.html")
- assert page.url == server.PREFIX + "/first.html"
-
- await page.click("a#forward")
- await page.wait_for_url("**/second.html")
- assert page.url == server.PREFIX + "/second.html"
-
-
-async def test_wait_for_url_should_work_with_url_match_for_same_document_navigations(
- page: Page, server: Server
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- await page.evaluate("history.pushState({}, '', '/first.html')")
- await page.evaluate("history.pushState({}, '', '/second.html')")
- await page.evaluate("history.pushState({}, '', '/third.html')")
- await page.wait_for_url(re.compile(r"third\.html"))
- assert "/third.html" in page.url
-
-
-async def test_wait_for_url_should_work_with_commit(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- await page.evaluate("url => window.location.href = url", server.PREFIX + "/grid.html")
- await page.wait_for_url("**/grid.html", wait_until="commit")
- assert "grid.html" in page.url
diff --git a/tests/async/test_websocket.py b/tests/async/test_websocket.py
deleted file mode 100644
index 7679c76..0000000
--- a/tests/async/test_websocket.py
+++ /dev/null
@@ -1,193 +0,0 @@
-# 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
-from typing import Union
-
-import pytest
-from flaky import flaky
-
-from playwright.async_api import Error, Page, WebSocket
-from tests.server import Server, WebSocketProtocol
-
-
-async def test_should_work(page: Page, server: Server) -> None:
- server.send_on_web_socket_connection(b"incoming")
- value = await page.evaluate(
- """port => {
- let cb;
- const result = new Promise(f => cb = f);
- const ws = new WebSocket('ws://localhost:' + port + '/ws');
- ws.addEventListener('message', data => { ws.close(); cb(data.data); });
- return result;
- }""",
- server.PORT,
- )
- assert value == "incoming"
- pass
-
-
-async def test_should_emit_close_events(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- close_future: asyncio.Future[None] = asyncio.Future()
- async with page.expect_websocket() as ws_info:
- await page.evaluate(
- """port => {
- const ws = new WebSocket('ws://localhost:' + port + '/ws');
- ws.addEventListener('open', data => ws.close());
- }""",
- server.PORT,
- )
- ws = await ws_info.value
- ws.on("close", lambda ws: close_future.set_result(None))
- assert ws.url == f"ws://localhost:{server.PORT}/ws"
- assert repr(ws) == f""
- await close_future
- assert ws.is_closed()
-
-
-async def test_should_emit_frame_events(page: Page, server: Server) -> None:
- def _handle_ws_connection(ws: WebSocketProtocol) -> None:
- def _onMessage(payload: bytes, isBinary: bool) -> None:
- ws.sendMessage(b"incoming", False)
- ws.sendClose()
-
- setattr(ws, "onMessage", _onMessage)
-
- server.once_web_socket_connection(_handle_ws_connection)
- log = []
- socket_close_future: "asyncio.Future[None]" = asyncio.Future()
-
- def on_web_socket(ws: WebSocket) -> None:
- log.append("open")
-
- def _on_framesent(payload: Union[bytes, str]) -> None:
- assert isinstance(payload, str)
- log.append(f"sent<{payload}>")
-
- ws.on("framesent", _on_framesent)
-
- def _on_framereceived(payload: Union[bytes, str]) -> None:
- assert isinstance(payload, str)
- log.append(f"received<{payload}>")
-
- ws.on("framereceived", _on_framereceived)
-
- def _handle_close(ws: WebSocket) -> None:
- log.append("close")
- socket_close_future.set_result(None)
-
- ws.on("close", _handle_close)
-
- page.on("websocket", on_web_socket)
- async with page.expect_event("websocket"):
- await page.evaluate(
- """port => {
- const ws = new WebSocket('ws://localhost:' + port + '/ws');
- ws.addEventListener('open', () => ws.send('outgoing'));
- ws.addEventListener('message', () => ws.close())
- }""",
- server.PORT,
- )
- await socket_close_future
- assert log[0] == "open"
- assert log[3] == "close"
- log.sort()
- assert log == ["close", "open", "received", "sent"]
-
-
-async def test_should_emit_binary_frame_events(page: Page, server: Server) -> None:
- def _handle_ws_connection(ws: WebSocketProtocol) -> None:
- ws.sendMessage(b"incoming")
-
- def _onMessage(payload: bytes, isBinary: bool) -> None:
- if payload == b"echo-bin":
- ws.sendMessage(b"\x04\x02", True)
- ws.sendClose()
- if payload == b"echo-text":
- ws.sendMessage(b"text", False)
- ws.sendClose()
-
- setattr(ws, "onMessage", _onMessage)
-
- server.once_web_socket_connection(_handle_ws_connection)
- done_task: "asyncio.Future[None]" = asyncio.Future()
- sent = []
- received = []
-
- def on_web_socket(ws: WebSocket) -> None:
- ws.on("framesent", lambda payload: sent.append(payload))
- ws.on("framereceived", lambda payload: received.append(payload))
- ws.on("close", lambda _: done_task.set_result(None))
-
- page.on("websocket", on_web_socket)
- async with page.expect_event("websocket"):
- await page.evaluate(
- """port => {
- const ws = new WebSocket('ws://localhost:' + port + '/ws');
- ws.addEventListener('open', () => {
- const binary = new Uint8Array(5);
- for (let i = 0; i < 5; ++i)
- binary[i] = i;
- ws.send(binary);
- ws.send('echo-bin');
- });
- }""",
- server.PORT,
- )
- await done_task
- assert sent == [b"\x00\x01\x02\x03\x04", "echo-bin"]
- assert received == ["incoming", b"\x04\x02"]
-
-
-@flaky
-async def test_should_reject_wait_for_event_on_close_and_error(page: Page, server: Server) -> None:
- server.send_on_web_socket_connection(b"incoming")
- async with page.expect_event("websocket") as ws_info:
- await page.evaluate(
- """port => {
- window.ws = new WebSocket('ws://localhost:' + port + '/ws');
- }""",
- server.PORT,
- )
- ws = await ws_info.value
- await ws.wait_for_event("framereceived")
- with pytest.raises(Error) as exc_info:
- async with ws.expect_event("framesent"):
- await page.evaluate("window.ws.close()")
- assert exc_info.value.message == "Socket closed"
-
-
-async def test_should_emit_error_event(page: Page, server: Server, browser_name: str) -> None:
- future: "asyncio.Future[str]" = asyncio.Future()
-
- def _on_ws_socket_error(err: str) -> None:
- future.set_result(err)
-
- def _on_websocket(websocket: WebSocket) -> None:
- websocket.on("socketerror", _on_ws_socket_error)
-
- page.on(
- "websocket",
- _on_websocket,
- )
- await page.evaluate(
- """port => new WebSocket(`ws://localhost:${port}/bogus-ws`)""",
- server.PORT,
- )
- err = await future
- if browser_name == "firefox":
- assert err == "CLOSE_ABNORMAL"
- else:
- assert ": 404" in err
diff --git a/tests/async/test_worker.py b/tests/async/test_worker.py
deleted file mode 100644
index 219fad1..0000000
--- a/tests/async/test_worker.py
+++ /dev/null
@@ -1,191 +0,0 @@
-# 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
-from asyncio.futures import Future
-
-import pytest
-from flaky import flaky
-
-from playwright.async_api import Browser, ConsoleMessage, Error, Page, Worker
-from tests.server import Server
-from tests.utils import TARGET_CLOSED_ERROR_MESSAGE
-
-
-async def test_workers_page_workers(page: Page, server: Server) -> None:
- async with page.expect_worker() as worker_info:
- await page.goto(server.PREFIX + "/worker/worker.html")
- worker = await worker_info.value
- assert "worker.js" in worker.url
- assert repr(worker) == f""
-
- assert await worker.evaluate('() => self["workerFunction"]()') == "worker function result"
-
- await page.goto(server.EMPTY_PAGE)
- assert len(page.workers) == 0
-
-
-async def test_workers_should_emit_created_and_destroyed_events(page: Page) -> None:
- worker_obj = None
- async with page.expect_event("worker") as event_info:
- worker_obj = await page.evaluate_handle(
- "() => new Worker(URL.createObjectURL(new Blob(['1'], {type: 'application/javascript'})))"
- )
- worker = await event_info.value
- worker_this_obj = await worker.evaluate_handle("() => this")
- worker_destroyed_promise: Future[Worker] = asyncio.Future()
- worker.once("close", lambda w: worker_destroyed_promise.set_result(w))
- await page.evaluate("workerObj => workerObj.terminate()", worker_obj)
- assert await worker_destroyed_promise == worker
- with pytest.raises(Error) as exc:
- await worker_this_obj.get_property("self")
- assert TARGET_CLOSED_ERROR_MESSAGE in exc.value.message
-
-
-async def test_workers_should_report_console_logs(page: Page) -> None:
- async with page.expect_console_message() as message_info:
- await page.evaluate(
- '() => new Worker(URL.createObjectURL(new Blob(["console.log(1)"], {type: "application/javascript"})))'
- )
- message = await message_info.value
- assert message.text == "1"
-
-
-async def test_workers_should_have_JSHandles_for_console_logs(
- page: Page, browser_name: str
-) -> None:
- log_promise: "asyncio.Future[ConsoleMessage]" = asyncio.Future()
- page.on("console", lambda m: log_promise.set_result(m))
- await page.evaluate(
- "() => new Worker(URL.createObjectURL(new Blob(['console.log(1,2,3,this)'], {type: 'application/javascript'})))"
- )
- log = await log_promise
- if browser_name != "firefox":
- assert log.text == "1 2 3 DedicatedWorkerGlobalScope"
- else:
- assert log.text == "1 2 3 JSHandle@object"
- assert len(log.args) == 4
- assert await (await log.args[3].get_property("origin")).json_value() == "null"
-
-
-async def test_workers_should_evaluate(page: Page) -> None:
- async with page.expect_event("worker") as event_info:
- await page.evaluate(
- "() => new Worker(URL.createObjectURL(new Blob(['console.log(1)'], {type: 'application/javascript'})))"
- )
- worker = await event_info.value
- assert await worker.evaluate("1+1") == 2
-
-
-async def test_workers_should_report_errors(page: Page) -> None:
- error_promise: "asyncio.Future[Error]" = asyncio.Future()
- page.on("pageerror", lambda e: error_promise.set_result(e))
- await page.evaluate(
- """() => new Worker(URL.createObjectURL(new Blob([`
- setTimeout(() => {
- // Do a console.log just to check that we do not confuse it with an error.
- console.log('hey');
- throw new Error('this is my error');
- })
- `], {type: 'application/javascript'})))"""
- )
- error_log = await error_promise
- assert "this is my error" in error_log.message
-
-
-@flaky # Upstream flaky
-async def test_workers_should_clear_upon_navigation(server: Server, page: Page) -> None:
- await page.goto(server.EMPTY_PAGE)
- async with page.expect_event("worker") as event_info:
- await page.evaluate(
- '() => new Worker(URL.createObjectURL(new Blob(["console.log(1)"], {type: "application/javascript"})))'
- )
- worker = await event_info.value
- assert len(page.workers) == 1
- destroyed = []
- worker.once("close", lambda _: destroyed.append(True))
- await page.goto(server.PREFIX + "/one-style.html")
- assert destroyed == [True]
- assert len(page.workers) == 0
-
-
-@flaky # Upstream flaky
-async def test_workers_should_clear_upon_cross_process_navigation(
- server: Server, page: Page
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- async with page.expect_event("worker") as event_info:
- await page.evaluate(
- "() => new Worker(URL.createObjectURL(new Blob(['console.log(1)'], {type: 'application/javascript'})))"
- )
- worker = await event_info.value
- assert len(page.workers) == 1
- destroyed = []
- worker.once("close", lambda _: destroyed.append(True))
- await page.goto(server.CROSS_PROCESS_PREFIX + "/empty.html")
- assert destroyed == [True]
- assert len(page.workers) == 0
-
-
-@pytest.mark.skip_browser("firefox") # https://github.com/microsoft/playwright/issues/21760
-async def test_workers_should_report_network_activity(page: Page, server: Server) -> None:
- async with page.expect_worker() as worker_info:
- await page.goto(server.PREFIX + "/worker/worker.html")
- worker = await worker_info.value
- url = server.PREFIX + "/one-style.css"
- async with page.expect_request(url) as request_info, page.expect_response(url) as response_info:
- await worker.evaluate(
- "url => fetch(url).then(response => response.text()).then(console.log)", url
- )
- request = await request_info.value
- response = await response_info.value
- assert request.url == url
- assert response.request == request
- assert response.ok
-
-
-@pytest.mark.skip_browser("firefox") # https://github.com/microsoft/playwright/issues/21760
-async def test_workers_should_report_network_activity_on_worker_creation(
- page: Page, server: Server
-) -> None:
- # Chromium needs waitForDebugger enabled for this one.
- await page.goto(server.EMPTY_PAGE)
- url = server.PREFIX + "/one-style.css"
- async with page.expect_request(url) as request_info, page.expect_response(url) as response_info:
- await page.evaluate(
- """url => new Worker(URL.createObjectURL(new Blob([`
- fetch("${url}").then(response => response.text()).then(console.log);
- `], {type: 'application/javascript'})))""",
- url,
- )
- request = await request_info.value
- response = await response_info.value
- assert request.url == url
- assert response.request == request
- assert response.ok
-
-
-async def test_workers_should_format_number_using_context_locale(
- browser: Browser, server: Server
-) -> None:
- context = await browser.new_context(locale="ru-RU")
- page = await context.new_page()
- await page.goto(server.EMPTY_PAGE)
- async with page.expect_worker() as worker_info:
- await page.evaluate(
- "() => new Worker(URL.createObjectURL(new Blob(['console.log(1)'], {type: 'application/javascript'})))"
- )
- worker = await worker_info.value
- assert await worker.evaluate("() => (10000.20).toLocaleString()") == "10\u00A0000,2"
- await context.close()
diff --git a/tests/async/utils.py b/tests/async/utils.py
deleted file mode 100644
index 546952d..0000000
--- a/tests/async/utils.py
+++ /dev/null
@@ -1,75 +0,0 @@
-# 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 re
-from typing import Any, List, cast
-
-from playwright.async_api import (
- ElementHandle,
- Error,
- Frame,
- Page,
- Selectors,
- ViewportSize,
-)
-
-
-class Utils:
- async def attach_frame(self, page: Page, frame_id: str, url: str) -> Frame:
- handle = await page.evaluate_handle(
- """async ({ frame_id, url }) => {
- const frame = document.createElement('iframe');
- frame.src = url;
- frame.id = frame_id;
- document.body.appendChild(frame);
- await new Promise(x => frame.onload = x);
- return frame;
- }""",
- {"frame_id": frame_id, "url": url},
- )
- frame = await cast(ElementHandle, handle.as_element()).content_frame()
- assert frame
- return frame
-
- async def detach_frame(self, page: Page, frame_id: str) -> None:
- await page.evaluate("frame_id => document.getElementById(frame_id).remove()", frame_id)
-
- def dump_frames(self, frame: Frame, indentation: str = "") -> List[str]:
- indentation = indentation or ""
- description = re.sub(r":\d+/", ":/", frame.url)
- if frame.name:
- description += " (" + frame.name + ")"
- result = [indentation + description]
- sorted_frames = sorted(frame.child_frames, key=lambda frame: frame.url + frame.name)
- for child in sorted_frames:
- result = result + utils.dump_frames(child, " " + indentation)
- return result
-
- async def verify_viewport(self, page: Page, width: int, height: int) -> None:
- assert cast(ViewportSize, page.viewport_size)["width"] == width
- assert cast(ViewportSize, page.viewport_size)["height"] == height
- assert await page.evaluate("window.innerWidth") == width
- assert await page.evaluate("window.innerHeight") == height
-
- async def register_selector_engine(
- self, selectors: Selectors, *args: Any, **kwargs: Any
- ) -> None:
- try:
- await selectors.register(*args, **kwargs)
- except Error as exc:
- if "has been already registered" not in exc.message:
- raise exc
-
-
-utils = Utils()
diff --git a/tests/async_imp/__init__.py b/tests/async_imp/__init__.py
deleted file mode 100644
index e69de29..0000000
diff --git a/tests/async_imp/conftest.py b/tests/async_imp/conftest.py
deleted file mode 100644
index 268c8a4..0000000
--- a/tests/async_imp/conftest.py
+++ /dev/null
@@ -1,139 +0,0 @@
-# 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
-from typing import Any, AsyncGenerator, Awaitable, Callable, Dict, Generator, List
-
-import pytest
-
-from playwright.async_api import (
- Browser,
- BrowserContext,
- BrowserType,
- Page,
- Playwright,
- Selectors,
- async_playwright,
-)
-
-from .utils import Utils
-from .utils import utils as utils_object
-
-
-@pytest.fixture
-def utils() -> Generator[Utils, None, None]:
- yield utils_object
-
-
-# Will mark all the tests as async
-def pytest_collection_modifyitems(items: List[pytest.Item]) -> None:
- for item in items:
- item.add_marker(pytest.mark.asyncio)
-
-
-@pytest.fixture(scope="session")
-async def playwright() -> AsyncGenerator[Playwright, None]:
- async with async_playwright() as playwright_object:
- yield playwright_object
-
-
-@pytest.fixture(scope="session")
-def browser_type(playwright: Playwright, browser_name: str) -> BrowserType:
- if browser_name == "chromium":
- return playwright.chromium
- if browser_name == "firefox":
- return playwright.firefox
- if browser_name == "webkit":
- return playwright.webkit
- raise Exception(f"Invalid browser_name: {browser_name}")
-
-
-@pytest.fixture(scope="session")
-async def browser_factory(
- launch_arguments: Dict, browser_type: BrowserType
-) -> AsyncGenerator[Callable[..., Awaitable[Browser]], None]:
- browsers = []
-
- async def launch(**kwargs: Any) -> Browser:
- browser = await browser_type.launch(**launch_arguments, **kwargs)
- browsers.append(browser)
- return browser
-
- yield launch
- for browser in browsers:
- await browser.close()
-
-
-@pytest.fixture(scope="session")
-async def browser(
- browser_factory: "Callable[..., asyncio.Future[Browser]]",
-) -> AsyncGenerator[Browser, None]:
- browser = await browser_factory()
- yield browser
- await browser.close()
-
-
-@pytest.fixture(scope="session")
-async def browser_version(browser: Browser) -> str:
- return browser.version
-
-
-@pytest.fixture
-async def context_factory(
- browser: Browser,
-) -> AsyncGenerator["Callable[..., Awaitable[BrowserContext]]", None]:
- contexts = []
-
- async def launch(**kwargs: Any) -> BrowserContext:
- context = await browser.new_context(**kwargs)
- contexts.append(context)
- return context
-
- yield launch
- for context in contexts:
- await context.close()
-
-
-@pytest.fixture(scope="session")
-async def default_same_site_cookie_value(browser_name: str, is_linux: bool) -> str:
- if browser_name == "chromium":
- return "Lax"
- if browser_name == "firefox":
- return "None"
- if browser_name == "webkit" and is_linux:
- return "Lax"
- if browser_name == "webkit" and not is_linux:
- return "None"
- raise Exception(f"Invalid browser_name: {browser_name}")
-
-
-@pytest.fixture
-async def context(
- context_factory: "Callable[..., asyncio.Future[BrowserContext]]",
-) -> AsyncGenerator[BrowserContext, None]:
- context = await context_factory()
- yield context
- await context.close()
-
-
-@pytest.fixture
-async def page(context: BrowserContext) -> AsyncGenerator[Page, None]:
- page = await context.new_page()
- yield page
- await page.close()
-
-
-@pytest.fixture(scope="session")
-def selectors(playwright: Playwright) -> Selectors:
- return playwright.selectors
diff --git a/tests/async_imp/test_frames.py b/tests/async_imp/test_frames.py
deleted file mode 100644
index 8deb70c..0000000
--- a/tests/async_imp/test_frames.py
+++ /dev/null
@@ -1,280 +0,0 @@
-# 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
-from typing import Optional
-
-import pytest
-
-from playwright.async_api import Error, Page
-from tests.server import Server
-
-from .utils import Utils
-
-
-async def test_evaluate_handle(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- main_frame = page.main_frame
- assert main_frame.page == page
- window_handle = await main_frame.evaluate_handle("window")
- assert window_handle
-
-
-async def test_frame_element(page: Page, server: Server, utils: Utils) -> None:
- await page.goto(server.EMPTY_PAGE)
- frame1 = await utils.attach_frame(page, "frame1", server.EMPTY_PAGE)
- assert frame1
- await utils.attach_frame(page, "frame2", server.EMPTY_PAGE)
- frame3 = await utils.attach_frame(page, "frame3", server.EMPTY_PAGE)
- assert frame3
- frame1handle1 = await page.query_selector("#frame1")
- assert frame1handle1
- frame1handle2 = await frame1.frame_element()
- frame3handle1 = await page.query_selector("#frame3")
- assert frame3handle1
- frame3handle2 = await frame3.frame_element()
- assert await frame1handle1.evaluate("(a, b) => a === b", frame1handle2)
- assert await frame3handle1.evaluate("(a, b) => a === b", frame3handle2)
- assert await frame1handle1.evaluate("(a, b) => a === b", frame3handle1) is False
-
-
-async def test_frame_element_with_content_frame(page: Page, server: Server, utils: Utils) -> None:
- await page.goto(server.EMPTY_PAGE)
- frame = await utils.attach_frame(page, "frame1", server.EMPTY_PAGE)
- handle = await frame.frame_element()
- content_frame = await handle.content_frame()
- assert content_frame == frame
-
-
-async def test_frame_element_throw_when_detached(page: Page, server: Server, utils: Utils) -> None:
- await page.goto(server.EMPTY_PAGE)
- frame1 = await utils.attach_frame(page, "frame1", server.EMPTY_PAGE)
- await page.eval_on_selector("#frame1", "e => e.remove()")
- error: Optional[Error] = None
- try:
- await frame1.frame_element()
- except Error as e:
- error = e
- assert error
- assert error.message == "Frame.frame_element: Frame has been detached."
-
-
-async def test_evaluate_throw_for_detached_frames(page: Page, server: Server, utils: Utils) -> None:
- frame1 = await utils.attach_frame(page, "frame1", server.EMPTY_PAGE)
- assert frame1
- await utils.detach_frame(page, "frame1")
- error: Optional[Error] = None
- try:
- await frame1.evaluate("7 * 8")
- except Error as e:
- error = e
- assert error
- assert "Frame was detached" in error.message
-
-
-async def test_evaluate_isolated_between_frames(page: Page, server: Server, utils: Utils) -> None:
- await page.goto(server.EMPTY_PAGE)
- await utils.attach_frame(page, "frame1", server.EMPTY_PAGE)
- assert len(page.frames) == 2
- [frame1, frame2] = page.frames
- assert frame1 != frame2
-
- await asyncio.gather(frame1.evaluate("window.a = 1"), frame2.evaluate("window.a = 2"))
- [a1, a2] = await asyncio.gather(frame1.evaluate("window.a"), frame2.evaluate("window.a"))
- assert a1 == 1
- assert a2 == 2
-
-
-async def test_should_handle_nested_frames(page: Page, server: Server, utils: Utils) -> None:
- await page.goto(server.PREFIX + "/frames/nested-frames.html")
- assert utils.dump_frames(page.main_frame) == [
- "http://localhost:/frames/nested-frames.html",
- " http://localhost:/frames/frame.html (aframe)",
- " http://localhost:/frames/two-frames.html (2frames)",
- " http://localhost:/frames/frame.html (dos)",
- " http://localhost:/frames/frame.html (uno)",
- ]
-
-
-async def test_should_send_events_when_frames_are_manipulated_dynamically(
- page: Page, server: Server, utils: Utils
-) -> None:
- await page.goto(server.EMPTY_PAGE)
- # validate frameattached events
- attached_frames = []
- page.on("frameattached", lambda frame: attached_frames.append(frame))
- await utils.attach_frame(page, "frame1", "./assets/frame.html")
- assert len(attached_frames) == 1
- assert "/assets/frame.html" in attached_frames[0].url
-
- # validate framenavigated events
- navigated_frames = []
- page.on("framenavigated", lambda frame: navigated_frames.append(frame))
- await page.evaluate(
- """() => {
- frame = document.getElementById('frame1')
- frame.src = './empty.html'
- return new Promise(x => frame.onload = x)
- }"""
- )
-
- assert len(navigated_frames) == 1
- assert navigated_frames[0].url == server.EMPTY_PAGE
-
- # validate framedetached events
- detached_frames = []
- page.on("framedetached", lambda frame: detached_frames.append(frame))
- await utils.detach_frame(page, "frame1")
- assert len(detached_frames) == 1
- assert detached_frames[0].is_detached()
-
-
-async def test_framenavigated_when_navigating_on_anchor_urls(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- async with page.expect_event("framenavigated"):
- await page.goto(server.EMPTY_PAGE + "#foo")
- assert page.url == server.EMPTY_PAGE + "#foo"
-
-
-async def test_persist_main_frame_on_cross_process_navigation(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- main_frame = page.main_frame
- await page.goto(server.CROSS_PROCESS_PREFIX + "/empty.html")
- assert page.main_frame == main_frame
-
-
-async def test_should_not_send_attach_detach_events_for_main_frame(
- page: Page, server: Server
-) -> None:
- has_events = []
- page.on("frameattached", lambda frame: has_events.append(True))
- page.on("framedetached", lambda frame: has_events.append(True))
- await page.goto(server.EMPTY_PAGE)
- assert has_events == []
-
-
-async def test_detach_child_frames_on_navigation(page: Page, server: Server) -> None:
- attached_frames = []
- detached_frames = []
- navigated_frames = []
- page.on("frameattached", lambda frame: attached_frames.append(frame))
- page.on("framedetached", lambda frame: detached_frames.append(frame))
- page.on("framenavigated", lambda frame: navigated_frames.append(frame))
- await page.goto(server.PREFIX + "/frames/nested-frames.html")
- assert len(attached_frames) == 4
- assert len(detached_frames) == 0
- assert len(navigated_frames) == 5
-
- attached_frames = []
- detached_frames = []
- navigated_frames = []
- await page.goto(server.EMPTY_PAGE)
- assert len(attached_frames) == 0
- assert len(detached_frames) == 4
- assert len(navigated_frames) == 1
-
-
-async def test_framesets(page: Page, server: Server) -> None:
- attached_frames = []
- detached_frames = []
- navigated_frames = []
- page.on("frameattached", lambda frame: attached_frames.append(frame))
- page.on("framedetached", lambda frame: detached_frames.append(frame))
- page.on("framenavigated", lambda frame: navigated_frames.append(frame))
- await page.goto(server.PREFIX + "/frames/frameset.html")
- assert len(attached_frames) == 4
- assert len(detached_frames) == 0
- assert len(navigated_frames) == 5
-
- attached_frames = []
- detached_frames = []
- navigated_frames = []
- await page.goto(server.EMPTY_PAGE)
- assert len(attached_frames) == 0
- assert len(detached_frames) == 4
- assert len(navigated_frames) == 1
-
-
-async def test_frame_from_inside_shadow_dom(page: Page, server: Server) -> None:
- await page.goto(server.PREFIX + "/shadow.html")
- await page.evaluate(
- """async url => {
- frame = document.createElement('iframe');
- frame.src = url;
- document.body.shadowRoot.appendChild(frame);
- await new Promise(x => frame.onload = x);
- }""",
- server.EMPTY_PAGE,
- )
- assert len(page.frames) == 2
- assert page.frames[1].url == server.EMPTY_PAGE
-
-
-async def test_frame_name(page: Page, server: Server, utils: Utils) -> None:
- await utils.attach_frame(page, "theFrameId", server.EMPTY_PAGE)
- await page.evaluate(
- """url => {
- frame = document.createElement('iframe');
- frame.name = 'theFrameName';
- frame.src = url;
- document.body.appendChild(frame);
- return new Promise(x => frame.onload = x);
- }""",
- server.EMPTY_PAGE,
- )
- assert page.frames[0].name == ""
- assert page.frames[1].name == "theFrameId"
- assert page.frames[2].name == "theFrameName"
-
-
-async def test_frame_parent(page: Page, server: Server, utils: Utils) -> None:
- await utils.attach_frame(page, "frame1", server.EMPTY_PAGE)
- await utils.attach_frame(page, "frame2", server.EMPTY_PAGE)
- assert page.frames[0].parent_frame is None
- assert page.frames[1].parent_frame == page.main_frame
- assert page.frames[2].parent_frame == page.main_frame
-
-
-async def test_should_report_different_frame_instance_when_frame_re_attaches(
- page: Page, server: Server, utils: Utils
-) -> None:
- frame1 = await utils.attach_frame(page, "frame1", server.EMPTY_PAGE)
- await page.evaluate(
- """() => {
- window.frame = document.querySelector('#frame1')
- window.frame.remove()
- }"""
- )
-
- assert frame1.is_detached()
- async with page.expect_event("frameattached") as frame2_info:
- await page.evaluate("() => document.body.appendChild(window.frame)")
-
- frame2 = await frame2_info.value
- assert frame2.is_detached() is False
- assert frame1 != frame2
-
-
-async def test_strict_mode(page: Page, server: Server) -> None:
- await page.goto(server.EMPTY_PAGE)
- await page.set_content(
- """
- Hello
- Hello
- """
- )
- with pytest.raises(Error):
- await page.text_content("button", strict=True)
- with pytest.raises(Error):
- await page.query_selector("button", strict=True)
diff --git a/tests/async_imp/utils.py b/tests/async_imp/utils.py
deleted file mode 100644
index 546952d..0000000
--- a/tests/async_imp/utils.py
+++ /dev/null
@@ -1,75 +0,0 @@
-# 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 re
-from typing import Any, List, cast
-
-from playwright.async_api import (
- ElementHandle,
- Error,
- Frame,
- Page,
- Selectors,
- ViewportSize,
-)
-
-
-class Utils:
- async def attach_frame(self, page: Page, frame_id: str, url: str) -> Frame:
- handle = await page.evaluate_handle(
- """async ({ frame_id, url }) => {
- const frame = document.createElement('iframe');
- frame.src = url;
- frame.id = frame_id;
- document.body.appendChild(frame);
- await new Promise(x => frame.onload = x);
- return frame;
- }""",
- {"frame_id": frame_id, "url": url},
- )
- frame = await cast(ElementHandle, handle.as_element()).content_frame()
- assert frame
- return frame
-
- async def detach_frame(self, page: Page, frame_id: str) -> None:
- await page.evaluate("frame_id => document.getElementById(frame_id).remove()", frame_id)
-
- def dump_frames(self, frame: Frame, indentation: str = "") -> List[str]:
- indentation = indentation or ""
- description = re.sub(r":\d+/", ":/", frame.url)
- if frame.name:
- description += " (" + frame.name + ")"
- result = [indentation + description]
- sorted_frames = sorted(frame.child_frames, key=lambda frame: frame.url + frame.name)
- for child in sorted_frames:
- result = result + utils.dump_frames(child, " " + indentation)
- return result
-
- async def verify_viewport(self, page: Page, width: int, height: int) -> None:
- assert cast(ViewportSize, page.viewport_size)["width"] == width
- assert cast(ViewportSize, page.viewport_size)["height"] == height
- assert await page.evaluate("window.innerWidth") == width
- assert await page.evaluate("window.innerHeight") == height
-
- async def register_selector_engine(
- self, selectors: Selectors, *args: Any, **kwargs: Any
- ) -> None:
- try:
- await selectors.register(*args, **kwargs)
- except Error as exc:
- if "has been already registered" not in exc.message:
- raise exc
-
-
-utils = Utils()
diff --git a/tests/conftest.py b/tests/conftest.py
deleted file mode 100644
index e0e00ad..0000000
--- a/tests/conftest.py
+++ /dev/null
@@ -1,302 +0,0 @@
-# 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 inspect
-import io
-import json
-import os
-import subprocess
-import sys
-from pathlib import Path
-from typing import Any, AsyncGenerator, Callable, Dict, Generator, List, Optional, cast
-
-import playwright
-import playwright._impl._path_utils
-import pytest
-from PIL import Image
-from pixelmatch import pixelmatch
-from pixelmatch.contrib.PIL import from_PIL_to_raw_data
-from playwright._impl._path_utils import get_file_dirname
-
-from .server import Server, test_server
-
-_dirname = get_file_dirname()
-
-
-"""
-Patch playwright to not rely on module path for assets.
-"""
-
-original_get_file_dirname = playwright._impl._path_utils.get_file_dirname
-
-
-@pytest.hookimpl(tryfirst=True)
-def pytest_configure(config):
- def patched_get_file_dirname():
- return _dirname
-
- playwright._impl._path_utils.get_file_dirname = patched_get_file_dirname
-
-
-@pytest.hookimpl(trylast=True)
-def pytest_unconfigure(config):
- playwright._impl._path_utils.get_file_dirname = original_get_file_dirname
-
-
-def pytest_generate_tests(metafunc: pytest.Metafunc) -> None:
- if "browser_name" in metafunc.fixturenames:
- browsers = ["firefox"]
- metafunc.parametrize("browser_name", browsers, scope="session")
-
-
-"""
-Playwright fixtures.
-"""
-
-
-@pytest.fixture(scope="session")
-def event_loop() -> Generator[asyncio.AbstractEventLoop, None, None]:
- loop = asyncio.get_event_loop()
- yield loop
- loop.close()
-
-
-@pytest.fixture(scope="session")
-def assetdir() -> Path:
- return _dirname / "assets"
-
-
-@pytest.fixture(scope="session")
-def headless(pytestconfig: pytest.Config) -> bool:
- return pytestconfig.getoption("--headless") or os.getenv("HEADLESS", False)
-
-
-@pytest.fixture(scope="session")
-def launch_arguments(pytestconfig: pytest.Config, headless: bool) -> Dict:
- args = {
- "headless": headless,
- "channel": pytestconfig.getoption("--browser-channel"),
- }
- executable_path = os.getenv("CAMOUFOX_EXECUTABLE_PATH", None)
- if executable_path:
- args["executable_path"] = os.path.abspath(executable_path)
- return args
-
-
-@pytest.fixture
-def server() -> Generator[Server, None, None]:
- yield test_server.server
-
-
-@pytest.fixture
-def https_server() -> Generator[Server, None, None]:
- yield test_server.https_server
-
-
-@pytest.fixture(autouse=True, scope="session")
-async def start_server() -> AsyncGenerator[None, None]:
- test_server.start()
- yield
- test_server.stop()
-
-
-@pytest.fixture(autouse=True)
-def after_each_hook() -> Generator[None, None, None]:
- yield
- test_server.reset()
-
-
-@pytest.fixture(scope="session")
-def browser_name(pytestconfig: pytest.Config) -> str:
- # Always use Firefox
- return 'firefox'
-
-
-@pytest.fixture(scope="session")
-def browser_channel(pytestconfig: pytest.Config) -> Optional[str]:
- return cast(Optional[str], pytestconfig.getoption("--browser-channel"))
-
-
-@pytest.fixture(scope="session")
-def is_webkit(browser_name: str) -> bool:
- return browser_name == "webkit"
-
-
-@pytest.fixture(scope="session")
-def is_firefox(browser_name: str) -> bool:
- return browser_name == "firefox"
-
-
-@pytest.fixture(scope="session")
-def is_chromium(browser_name: str) -> bool:
- return browser_name == "chromium"
-
-
-@pytest.fixture(scope="session")
-def is_win() -> bool:
- return sys.platform == "win32"
-
-
-@pytest.fixture(scope="session")
-def is_linux() -> bool:
- return sys.platform == "linux"
-
-
-@pytest.fixture(scope="session")
-def is_mac() -> bool:
- return sys.platform == "darwin"
-
-
-"""
-Helper to skip tests by browser or platform.
-"""
-
-
-def _get_skiplist(request: pytest.FixtureRequest, values: List[str], value_name: str) -> List[str]:
- skipped_values = []
- # Allowlist
- only_marker = request.node.get_closest_marker(f"only_{value_name}")
- if only_marker:
- skipped_values = values
- skipped_values.remove(only_marker.args[0])
-
- # Denylist
- skip_marker = request.node.get_closest_marker(f"skip_{value_name}")
- if skip_marker:
- skipped_values.append(skip_marker.args[0])
-
- return skipped_values
-
-
-@pytest.fixture(autouse=True)
-def skip_by_browser(request: pytest.FixtureRequest, browser_name: str) -> None:
- skip_browsers_names = _get_skiplist(request, ["chromium", "firefox", "webkit"], "browser")
-
- if browser_name in skip_browsers_names:
- pytest.skip(f"skipped for this browser: {browser_name}")
-
-
-@pytest.fixture(autouse=True)
-def skip_by_platform(request: pytest.FixtureRequest) -> None:
- skip_platform_names = _get_skiplist(request, ["win32", "linux", "darwin"], "platform")
-
- if sys.platform in skip_platform_names:
- pytest.skip(f"skipped on this platform: {sys.platform}")
-
-
-def pytest_addoption(parser: pytest.Parser) -> None:
- group = parser.getgroup("playwright", "Playwright")
- parser.addoption(
- "--headless",
- action="store_true",
- default=False,
- help="Run tests in headless mode.",
- )
- group.addoption(
- "--browser-channel",
- action="store",
- default=None,
- help="Browser channel to be used.",
- )
-
-
-@pytest.fixture(scope="session")
-def assert_to_be_golden(browser_name: str) -> Callable[[bytes, str], None]:
- def compare(received_raw: bytes, golden_name: str) -> None:
- golden_file_path = _dirname / f"golden-{browser_name}" / golden_name
- try:
- golden_file = golden_file_path.read_bytes()
- received_image = Image.open(io.BytesIO(received_raw))
- golden_image = Image.open(io.BytesIO(golden_file))
-
- if golden_image.size != received_image.size:
- pytest.fail("Image size differs to golden image")
- return
- diff_pixels = pixelmatch(
- from_PIL_to_raw_data(received_image),
- from_PIL_to_raw_data(golden_image),
- golden_image.size[0],
- golden_image.size[1],
- threshold=0.2,
- )
- assert diff_pixels == 0
- except Exception:
- if os.getenv("PW_WRITE_SCREENSHOT"):
- golden_file_path.parent.mkdir(parents=True, exist_ok=True)
- golden_file_path.write_bytes(received_raw)
- print(f"Wrote {golden_file_path}")
- raise
-
- return compare
-
-
-class RemoteServer:
- def __init__(self, browser_name: str, launch_server_options: Dict, tmpfile: Path) -> None:
- driver_dir = Path(inspect.getfile(playwright)).parent / "driver"
- if sys.platform == "win32":
- node_executable = driver_dir / "node.exe"
- else:
- node_executable = driver_dir / "node"
- cli_js = driver_dir / "package" / "cli.js"
- tmpfile.write_text(json.dumps(launch_server_options))
- self.process = subprocess.Popen(
- [
- str(node_executable),
- str(cli_js),
- "launch-server",
- "--browser",
- browser_name,
- "--config",
- str(tmpfile),
- ],
- stdout=subprocess.PIPE,
- stderr=sys.stderr,
- cwd=driver_dir,
- )
- assert self.process.stdout
- self.ws_endpoint = self.process.stdout.readline().decode().strip()
- self.process.stdout.close()
-
- def kill(self) -> None:
- # Send the signal to all the process groups
- if self.process.poll() is not None:
- return
- self.process.kill()
- self.process.wait()
-
-
-@pytest.fixture
-def launch_server(
- browser_name: str, launch_arguments: Dict, tmp_path: Path
-) -> Generator[Callable[..., RemoteServer], None, None]:
- remotes: List[RemoteServer] = []
-
- def _launch_server(**kwargs: Dict[str, Any]) -> RemoteServer:
- remote = RemoteServer(
- browser_name,
- {
- **launch_arguments,
- **kwargs,
- },
- tmp_path / f"settings-{len(remotes)}.json",
- )
- remotes.append(remote)
- return remote
-
- yield _launch_server
-
- for remote in remotes:
- remote.kill()
- remote.kill()
diff --git a/tests/golden-firefox/grid-cell-0.png b/tests/golden-firefox/grid-cell-0.png
deleted file mode 100644
index 4677bdb..0000000
Binary files a/tests/golden-firefox/grid-cell-0.png and /dev/null differ
diff --git a/tests/golden-firefox/mask-should-work-with-element-handle.png b/tests/golden-firefox/mask-should-work-with-element-handle.png
deleted file mode 100644
index 682da85..0000000
Binary files a/tests/golden-firefox/mask-should-work-with-element-handle.png and /dev/null differ
diff --git a/tests/golden-firefox/mask-should-work-with-locator.png b/tests/golden-firefox/mask-should-work-with-locator.png
deleted file mode 100644
index 682da85..0000000
Binary files a/tests/golden-firefox/mask-should-work-with-locator.png and /dev/null differ
diff --git a/tests/golden-firefox/mask-should-work-with-page.png b/tests/golden-firefox/mask-should-work-with-page.png
deleted file mode 100644
index 720828e..0000000
Binary files a/tests/golden-firefox/mask-should-work-with-page.png and /dev/null differ
diff --git a/tests/golden-firefox/mock-binary-response.png b/tests/golden-firefox/mock-binary-response.png
deleted file mode 100644
index e7eaf59..0000000
Binary files a/tests/golden-firefox/mock-binary-response.png and /dev/null differ
diff --git a/tests/golden-firefox/mock-svg.png b/tests/golden-firefox/mock-svg.png
deleted file mode 100644
index a9ee147..0000000
Binary files a/tests/golden-firefox/mock-svg.png and /dev/null differ
diff --git a/tests/golden-firefox/screenshot-element-bounding-box.png b/tests/golden-firefox/screenshot-element-bounding-box.png
deleted file mode 100644
index 9e208f8..0000000
Binary files a/tests/golden-firefox/screenshot-element-bounding-box.png and /dev/null differ
diff --git a/tests/golden-firefox/screenshot-sanity.png b/tests/golden-firefox/screenshot-sanity.png
deleted file mode 100644
index ecab61f..0000000
Binary files a/tests/golden-firefox/screenshot-sanity.png and /dev/null differ
diff --git a/tests/local-requirements.txt b/tests/local-requirements.txt
deleted file mode 100644
index 92e78ae..0000000
--- a/tests/local-requirements.txt
+++ /dev/null
@@ -1,25 +0,0 @@
-playwright
-auditwheel==6.1.0
-autobahn==23.1.2
-black==24.8.0
-flake8==7.1.1
-flaky==3.8.1
-mypy==1.11.1
-objgraph==3.6.1
-Pillow==10.4.0
-pixelmatch==0.3.0
-pre-commit==3.4.0
-pyOpenSSL==24.2.1
-pytest==8.3.2
-pytest-asyncio==0.21.2
-pytest-cov==5.0.0
-pytest-repeat==0.9.3
-pytest-timeout==2.3.1
-pytest-xdist==3.6.1
-requests==2.32.3
-service_identity==24.1.0
-setuptools==72.1.0
-twisted==24.7.0
-types-pyOpenSSL==24.1.0.20240722
-types-requests==2.32.0.20240712
-wheel==0.42.0
diff --git a/tests/pyproject.toml b/tests/pyproject.toml
deleted file mode 100644
index 4878d64..0000000
--- a/tests/pyproject.toml
+++ /dev/null
@@ -1,19 +0,0 @@
-[tool.pytest.ini_options]
-addopts = "-Wall -rsx -vv -s"
-markers = [
- "skip_browser",
- "only_browser",
- "skip_platform",
- "only_platform"
-]
-junit_family = "xunit2"
-asyncio_mode = "auto"
-
-[tool.pyright]
-pythonVersion = "3.8"
-reportMissingImports = false
-reportTypedDictNotRequiredAccess = false
-reportCallInDefaultInitializer = true
-reportOptionalSubscript = false
-reportUnboundVariable = false
-strictParameterNoneValue = false
diff --git a/tests/run-tests.sh b/tests/run-tests.sh
deleted file mode 100644
index 17821ab..0000000
--- a/tests/run-tests.sh
+++ /dev/null
@@ -1,77 +0,0 @@
-#!/bin/bash
-
-# Function to check if an argument is valid
-check_arg() {
- case "$1" in
- --headful)
- return 0
- ;;
- --executable-path)
- if [ -z "$2" ]; then
- echo "Error: --executable-path requires a path argument"
- return 1
- elif [ ! -e "$2" ]; then
- echo "Error: The path specified for --executable-path does not exist: $2"
- return 1
- fi
- return 0
- ;;
- *)
- echo "Error: Invalid argument '$1'. Only --headful and --executable-path are allowed."
- return 1
- ;;
- esac
-}
-
-# Check if venv exists, if not run setup-venv.sh
-if [ ! -d "venv" ]; then
- echo "Virtual environment not found. Running setup-venv.sh..."
- bash ./setup-venv.sh
- if [ $? -ne 0 ]; then
- echo "Failed to set up virtual environment. Exiting."
- exit 1
- fi
-fi
-
-# Validate arguments
-VALID_ARGS=("--headless") # Set headless as default
-i=1
-while [ $i -le $# ]; do
- arg="$1"
- case "$arg" in
- --executable-path)
- shift # move to the next argument
- if [ -z "$1" ]; then
- echo "Error: --executable-path requires a path argument"
- exit 1
- fi
- if check_arg "--executable-path" "$1"; then
- export CAMOUFOX_EXECUTABLE_PATH="$1"
- shift
- else
- exit 1
- fi
- ;;
- --headful)
- if check_arg "$arg"; then
- VALID_ARGS=() # Remove default --headless
- shift
- else
- exit 1
- fi
- ;;
- *)
- echo "Error: Invalid argument '$arg'. Only --headful and --executable-path are allowed."
- exit 1
- ;;
- esac
-done
-
-# Run pytest with validated arguments
-echo "Running pytest with arguments: ${VALID_ARGS[@]}"
-if [ -n "$CAMOUFOX_EXECUTABLE_PATH" ]; then
- echo "CAMOUFOX_EXECUTABLE_PATH set to: $CAMOUFOX_EXECUTABLE_PATH"
-fi
-
-echo venv/bin/pytest -vv "${VALID_ARGS[@]}" async/
-venv/bin/pytest -vv "${VALID_ARGS[@]}" async/
\ No newline at end of file
diff --git a/tests/server.py b/tests/server.py
deleted file mode 100644
index 1366345..0000000
--- a/tests/server.py
+++ /dev/null
@@ -1,299 +0,0 @@
-# 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 abc
-import asyncio
-import contextlib
-import gzip
-import mimetypes
-import os
-import socket
-import threading
-from contextlib import closing
-from http import HTTPStatus
-from pathlib import Path
-from typing import (
- Any,
- Callable,
- Dict,
- Generator,
- Generic,
- List,
- Optional,
- Set,
- Tuple,
- TypeVar,
- cast,
-)
-from urllib.parse import urlparse
-
-from autobahn.twisted.resource import WebSocketResource
-from autobahn.twisted.websocket import WebSocketServerFactory, WebSocketServerProtocol
-from OpenSSL import crypto
-from twisted.internet import reactor as _twisted_reactor
-from twisted.internet import ssl
-from twisted.internet.selectreactor import SelectReactor
-from twisted.web import http
-
-_dirname = Path(os.path.abspath(__file__)).parent
-reactor = cast(SelectReactor, _twisted_reactor)
-
-
-def find_free_port() -> int:
- with closing(socket.socket(socket.AF_INET, socket.SOCK_STREAM)) as s:
- s.bind(("", 0))
- s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
- return s.getsockname()[1]
-
-
-T = TypeVar("T")
-
-
-class ExpectResponse(Generic[T]):
- def __init__(self) -> None:
- self._value: T
-
- @property
- def value(self) -> T:
- if not hasattr(self, "_value"):
- raise ValueError("no received value")
- return self._value
-
-
-class TestServerRequest(http.Request):
- __test__ = False
- channel: "TestServerHTTPChannel"
- post_body: Optional[bytes] = None
-
- def process(self) -> None:
- server = self.channel.factory.server_instance
- if self.content:
- self.post_body = self.content.read()
- self.content.seek(0, 0)
- else:
- self.post_body = None
- uri = urlparse(self.uri.decode())
- path = uri.path
-
- request_subscriber = server.request_subscribers.get(path)
- if request_subscriber:
- request_subscriber._loop.call_soon_threadsafe(request_subscriber.set_result, self)
- server.request_subscribers.pop(path)
-
- if path == "/ws":
- server._ws_resource.render(self)
- return
-
- if server.auth.get(path):
- authorization_header = self.requestHeaders.getRawHeaders("authorization")
- creds_correct = False
- if authorization_header:
- creds_correct = server.auth.get(path) == (
- self.getUser().decode(),
- self.getPassword().decode(),
- )
- if not creds_correct:
- self.setHeader(b"www-authenticate", 'Basic realm="Secure Area"')
- self.setResponseCode(HTTPStatus.UNAUTHORIZED)
- self.finish()
- return
- if server.csp.get(path):
- self.setHeader(b"Content-Security-Policy", server.csp[path])
- if server.routes.get(path):
- server.routes[path](self)
- return
- file_content = None
- try:
- file_content = (server.static_path / path[1:]).read_bytes()
- content_type = mimetypes.guess_type(path)[0]
- if content_type and content_type.startswith("text/"):
- content_type += "; charset=utf-8"
- self.setHeader(b"Content-Type", content_type)
- self.setHeader(b"Cache-Control", "no-cache, no-store")
- if path in server.gzip_routes:
- self.setHeader("Content-Encoding", "gzip")
- self.write(gzip.compress(file_content))
- else:
- self.setHeader(b"Content-Length", str(len(file_content)))
- self.write(file_content)
- self.setResponseCode(HTTPStatus.OK)
- except (FileNotFoundError, IsADirectoryError, PermissionError):
- self.setResponseCode(HTTPStatus.NOT_FOUND)
- self.finish()
-
-
-class TestServerHTTPChannel(http.HTTPChannel):
- factory: "TestServerFactory"
- requestFactory = TestServerRequest
-
-
-class TestServerFactory(http.HTTPFactory):
- server_instance: "Server"
- protocol = TestServerHTTPChannel
-
-
-class Server:
- protocol = "http"
-
- def __init__(self) -> None:
- self.PORT = find_free_port()
- self.EMPTY_PAGE = f"{self.protocol}://localhost:{self.PORT}/empty.html"
- self.PREFIX = f"{self.protocol}://localhost:{self.PORT}"
- self.CROSS_PROCESS_PREFIX = f"{self.protocol}://127.0.0.1:{self.PORT}"
- # On Windows, this list can be empty, reporting text/plain for scripts.
- mimetypes.add_type("text/html", ".html")
- mimetypes.add_type("text/css", ".css")
- mimetypes.add_type("application/javascript", ".js")
- mimetypes.add_type("image/png", ".png")
- mimetypes.add_type("font/woff2", ".woff2")
-
- def __repr__(self) -> str:
- return self.PREFIX
-
- @abc.abstractmethod
- def listen(self, factory: TestServerFactory) -> None:
- pass
-
- def start(self) -> None:
- request_subscribers: Dict[str, asyncio.Future] = {}
- auth: Dict[str, Tuple[str, str]] = {}
- csp: Dict[str, str] = {}
- routes: Dict[str, Callable[[TestServerRequest], Any]] = {}
- gzip_routes: Set[str] = set()
- self.request_subscribers = request_subscribers
- self.auth = auth
- self.csp = csp
- self.routes = routes
- self._ws_handlers: List[Callable[["WebSocketProtocol"], None]] = []
- self.gzip_routes = gzip_routes
- self.static_path = _dirname / "assets"
- factory = TestServerFactory()
- factory.server_instance = self
-
- ws_factory = WebSocketServerFactory()
- ws_factory.protocol = WebSocketProtocol
- ws_factory.server_instance = self
- self._ws_resource = WebSocketResource(ws_factory)
-
- self.listen(factory)
-
- async def wait_for_request(self, path: str) -> TestServerRequest:
- if path in self.request_subscribers:
- return await self.request_subscribers[path]
- future: asyncio.Future["TestServerRequest"] = asyncio.Future()
- self.request_subscribers[path] = future
- return await future
-
- @contextlib.contextmanager
- def expect_request(self, path: str) -> Generator[ExpectResponse[TestServerRequest], None, None]:
- future = asyncio.create_task(self.wait_for_request(path))
-
- cb_wrapper: ExpectResponse[TestServerRequest] = ExpectResponse()
-
- def done_cb(task: asyncio.Task) -> None:
- cb_wrapper._value = future.result()
-
- future.add_done_callback(done_cb)
- yield cb_wrapper
-
- def set_auth(self, path: str, username: str, password: str) -> None:
- self.auth[path] = (username, password)
-
- def set_csp(self, path: str, value: str) -> None:
- self.csp[path] = value
-
- def reset(self) -> None:
- self.request_subscribers.clear()
- self.auth.clear()
- self.csp.clear()
- self.gzip_routes.clear()
- self.routes.clear()
- self._ws_handlers.clear()
-
- def set_route(self, path: str, callback: Callable[[TestServerRequest], Any]) -> None:
- self.routes[path] = callback
-
- def enable_gzip(self, path: str) -> None:
- self.gzip_routes.add(path)
-
- def set_redirect(self, from_: str, to: str) -> None:
- def handle_redirect(request: http.Request) -> None:
- request.setResponseCode(HTTPStatus.FOUND)
- request.setHeader("location", to)
- request.finish()
-
- self.set_route(from_, handle_redirect)
-
- def send_on_web_socket_connection(self, data: bytes) -> None:
- self.once_web_socket_connection(lambda ws: ws.sendMessage(data))
-
- def once_web_socket_connection(self, handler: Callable[["WebSocketProtocol"], None]) -> None:
- self._ws_handlers.append(handler)
-
-
-class HTTPServer(Server):
- def listen(self, factory: http.HTTPFactory) -> None:
- reactor.listenTCP(self.PORT, factory, interface="127.0.0.1")
- try:
- reactor.listenTCP(self.PORT, factory, interface="::1")
- except Exception:
- pass
-
-
-class HTTPSServer(Server):
- protocol = "https"
-
- def listen(self, factory: http.HTTPFactory) -> None:
- cert = ssl.PrivateCertificate.fromCertificateAndKeyPair(
- ssl.Certificate.loadPEM((_dirname / "testserver" / "cert.pem").read_bytes()),
- ssl.KeyPair.load(
- (_dirname / "testserver" / "key.pem").read_bytes(), crypto.FILETYPE_PEM
- ),
- )
- contextFactory = cert.options()
- reactor.listenSSL(self.PORT, factory, contextFactory, interface="127.0.0.1")
- try:
- reactor.listenSSL(self.PORT, factory, contextFactory, interface="::1")
- except Exception:
- pass
-
-
-class WebSocketProtocol(WebSocketServerProtocol):
- def onOpen(self) -> None:
- for handler in self.factory.server_instance._ws_handlers.copy():
- self.factory.server_instance._ws_handlers.remove(handler)
- handler(self)
-
-
-class TestServer:
- def __init__(self) -> None:
- self.server = HTTPServer()
- self.https_server = HTTPSServer()
-
- def start(self) -> None:
- self.server.start()
- self.https_server.start()
- self.thread = threading.Thread(target=lambda: reactor.run(installSignalHandlers=False))
- self.thread.start()
-
- def stop(self) -> None:
- reactor.stop()
- self.thread.join()
-
- def reset(self) -> None:
- self.server.reset()
- self.https_server.reset()
-
-
-test_server = TestServer()
diff --git a/tests/setup-venv.sh b/tests/setup-venv.sh
deleted file mode 100644
index 0a4fb47..0000000
--- a/tests/setup-venv.sh
+++ /dev/null
@@ -1,7 +0,0 @@
-#!/bin/bash
-
-python3 -m venv venv
-venv/bin/pip3 install -r local-requirements.txt
-
-# Install Firefox as well (Playwright freaks out when it's missing)
-venv/bin/playwright install firefox
diff --git a/tests/testserver/cert.pem b/tests/testserver/cert.pem
deleted file mode 100644
index fc692a6..0000000
--- a/tests/testserver/cert.pem
+++ /dev/null
@@ -1,28 +0,0 @@
------BEGIN CERTIFICATE-----
-MIIEsjCCApoCCQCIPLvQDgoZojANBgkqhkiG9w0BAQsFADAaMRgwFgYDVQQDDA9w
-dXBwZXRlZXItdGVzdHMwIBcNMTkwMjEzMTkwNzQzWhgPMzAxODA2MTYxOTA3NDNa
-MBoxGDAWBgNVBAMMD3B1cHBldGVlci10ZXN0czCCAiIwDQYJKoZIhvcNAQEBBQAD
-ggIPADCCAgoCggIBAJue1yqA4qn0SJR3rgTd6sCYVHMKqUouD0No09H7qf+5ZaIb
-3yGpC5J9Bsf/ZbvD5xpgqbGEYkHj7Qh6Z/cPCSHA+ZpsUzDXVrLFXrdwwiK1FrIS
-rDI2RYsiP+e52XPC/acWC/7f+E54C62oMjYojaVaDn8gu06gyS1rXK2JITQ6CrKn
-b+PVSkjtPB4ku245u1qCKoblkNEZSkEmw8Csl+gw6ydGqOSQAoo8rsDte5zCMnPX
-7XzL6EhRqpiVx7PCuQWnXhL7j9N214Pit7s7F8TeAA6yZR9oswW+h0dWO+XwocJ1
-rwkODXOngbCqO+GUxyuavIl2m0d2MP8n6Wa9RVqYetmPQzafKkR5hjiV4mgCFqNQ
-bHMTjI6udcR+h5pYoWKxN9/gJaWwyAAzck0AiMeGVrvKR3JKACqlTMzy/Y30obRF
-dddURoFf2wjKJvuTK9hHI7pwM5tlPEwu9bTCWNA6XXs2Bq1f6N2OAKhpKOcihNem
-aeGUPmygLPb66z9JO75yZXM+1yk1ScXaNHWZLmluVpEPk7maWULpSpxPAlaN3PmK
-8lEihgfBBovampxZo8SvPEt+g5jGyPq9weNg8ic8476PuRVQdg7D8spVxl6whDlJ
-bcFojzgrX70t13jqZOtla4WK1vRnZAGplfoH0i5WvAVw+i5S/OVzsmNDtGFbAgMB
-AAEwDQYJKoZIhvcNAQELBQADggIBADUAjA/dH+b5UxDC5SL98w1hphw9PvD1cuGS
-sVnKPM236JoTiO3KVfm3NMBfSoBi1hPNkXzqr/R4xbyje4Kc4oYcdjGtpll3T5da
-wkx1+qumx6O2mEaOshxh76dfZfZne6SQphQKHw8PD10CfDb/NMnmdEbiOSENSqS4
-jGELuGviUl361oCBU45UEN7lfs7ANAhwSZyEO7deroyGdvsxfQUaqQrEQsG30jn3
-t0cCamYU6eK3bNR/yNXJrZFv3dzoquRY9H52YtVElRqdAIsNlnbxbqz0cm5xFKFt
-YTIrMSO1EvDTbB0PPwC5FJvONHhjwiWzgVXSnZrcs/05TsWWnSHH92S+wGCIBC+0
-6fcSKnjdBn9ks5TrDX0TRY6N890KyDQWxPRhHYrMVpn833WY8y/SguxqiMgLFgMD
-WLy6yZzJloW7NgpLGAfMA0nMG1O92hfKmQw82Pyf3SVXGTDiXiEOXn0vN6bsPaV/
-3Ws2LJQECnVfHj3TsuxdtwcO+VGcFCarMOqlhE6IlQzfK8ykYdP6wCkVgXEtiVCR
-T1OWUWCFowoFpwBFLf1lA065qsAymddnkrUEOMiScZ/3OZhmd+FvgQ+O0iYuqpeI
-xauiQ68+Jb4KjVWnu5QBVq8n1vUJ5+gAzowNMN9G+1+A282Ox23T48dce22BTS6B
-3Taaccm+
------END CERTIFICATE-----
diff --git a/tests/testserver/key.pem b/tests/testserver/key.pem
deleted file mode 100644
index e2ed680..0000000
--- a/tests/testserver/key.pem
+++ /dev/null
@@ -1,52 +0,0 @@
------BEGIN PRIVATE KEY-----
-MIIJQwIBADANBgkqhkiG9w0BAQEFAASCCS0wggkpAgEAAoICAQCbntcqgOKp9EiU
-d64E3erAmFRzCqlKLg9DaNPR+6n/uWWiG98hqQuSfQbH/2W7w+caYKmxhGJB4+0I
-emf3DwkhwPmabFMw11ayxV63cMIitRayEqwyNkWLIj/nudlzwv2nFgv+3/hOeAut
-qDI2KI2lWg5/ILtOoMkta1ytiSE0Ogqyp2/j1UpI7TweJLtuObtagiqG5ZDRGUpB
-JsPArJfoMOsnRqjkkAKKPK7A7XucwjJz1+18y+hIUaqYlcezwrkFp14S+4/TdteD
-4re7OxfE3gAOsmUfaLMFvodHVjvl8KHCda8JDg1zp4GwqjvhlMcrmryJdptHdjD/
-J+lmvUVamHrZj0M2nypEeYY4leJoAhajUGxzE4yOrnXEfoeaWKFisTff4CWlsMgA
-M3JNAIjHhla7ykdySgAqpUzM8v2N9KG0RXXXVEaBX9sIyib7kyvYRyO6cDObZTxM
-LvW0wljQOl17NgatX+jdjgCoaSjnIoTXpmnhlD5soCz2+us/STu+cmVzPtcpNUnF
-2jR1mS5pblaRD5O5mllC6UqcTwJWjdz5ivJRIoYHwQaL2pqcWaPErzxLfoOYxsj6
-vcHjYPInPOO+j7kVUHYOw/LKVcZesIQ5SW3BaI84K1+9Ldd46mTrZWuFitb0Z2QB
-qZX6B9IuVrwFcPouUvzlc7JjQ7RhWwIDAQABAoICAFUvM5SejHR/taMfh/A+EZxv
-RfrbISPr5or9vMU6vymuMIX2P8PLJvx+19Fuah/H8p8rvnffgXGT9FIpvvMsFdGW
-MotnNHqNxXWCOICthnc9LTk4o22w64xnqReNUgzd9b8agGJ58w/xAmOCqEmhFTgn
-/bt1DVLTDIyCMm8Dm1tdUjHNGaBbRph40+mkLbz+eSHoEqNY0lbDQzQ6pfi4AUcm
-T/Jl6VmDwwAsi3QsCvgaDUgAMI2ZiILdwUZY5sHtmx4PKZ22elpEuWAGIJCqni4z
-X1CsMlJpG2XPj3lrKMqLV+B8Tt3kBVUDoig0ZybqK8QgpYeRlxodBmEFVevZOzar
-r/qDRh+vrQQxjpFYfrMkPiueRmz0+K1a7KiKSmrjHIb9CTi3BpgEhawbsOB7M+9z
-G5Q7YtGbVyJPmEAAva89ZZqYvyAwxZk3V4pwpoUYzjgPiHm6Oq0vzKPuCgQxsYzx
-UrCVRo7pSE4tTin4SRThY2/yHiMJl8QY//MkahgY8KEHtXE36km6pMRH/ssdSm+C
-SNCOtzUDY8wpaDQ++aB29NWqgnSgwoBrRUXr5NHq+wNpWtmD7L0wDSKUCPfiCduR
-DoSHBIno5U2jgPrH5Wk7X7loG2XxiDR0qtNOiH24SCI+C1nsLRGBS2Tmo0Qby/Ll
-oYYCZ0U3S7wk9UY5HcuRAoIBAQDIl8HTaIuzyOrrpsRdUv8jAxnkdhVjYhWGp7mU
-5concRazcEO5/vDJlsIuQI/w7U+xS7PCBPRq7NxUtaUntlQ00s224Ws0sPHIWUD0
-NBsodTX8hik2PdmZ5ZbBHVaeVbMV/5zV8eOPGGCsAn//7l4YIp2I2Abs79leqSDI
-7tBpF4IsUq7xqcVZ1QhWBZmTqE4gYDVqFEVe9O6OmAdkM1qxVSur2E5Ib+islnu8
-yKlu0QlXg596zLVAjxajKYf20NXxh7O+xt5QDEy3dmJEhz5viS6eI7QECM7Lid2T
-c22mABSKzYfbwQroM9yBiI3p0zjwRhha0hRKocLkSiNUlOWHAoIBAQDGmwRM6Xmu
-j7/lV3KvrOmvcNIbUwMbYY/ATY3Wuph6GFjwdliRiju9F3ZUHMV+yNlVDqH3DeRC
-QwGKIcFiVk+4fq1AbWVCWk2MOf49akeJwqFzgF8nkxVXF9PS73VdEvreSvy7g89t
-ABqJN6pmGHWVkE1mf/3LJyS2Y7WCZqSaWG3TBZ2SRb2t/t/DnX1L6tzNMkuNAizA
-sDB3J1hH1eGcWn/24NB9sc7i2Bk+Cpi0S/xDn9FfoBo5U0p/lpopgfFoSeQZXq1A
-KIQdtUPLp3KR9EG/ItimfW875zqFe8bekB9/gakyLsbIyINz1iQQS1L1FFmOO8zN
-RtRmm3MrG9qNAoIBAQC1v2rLFgqeVwkjgvKgbDbnjkPDkIpIhfJjE00+8AV+PyUG
-aE21FJ0uyf4e0jiZXyu5xJGW1c5vozTvO7XsiXM6eVYSwaPVFg28LcKAgUWqHqlP
-qG9myhuDKVaymtaEl7mv0O5VmtlIKhpNP+aiCWQQEi0SdEmyHI+jCTK/XEJRNg+o
-ATKpm91IS5FF/8Tq2LAQ/ZroBn3kT6BmarEnxLADxNvQ1Cf50gvLdH2gy19ZHOWN
-+aBiL2B6oissotCifQ2bzgy6ao27kalhAU6AMNoNTQqEFm1gymo0WTH+C7PpmGEE
-cr0KC5rKUVMVuph6p/sLGTev8nCYPoDLP7FLTa25AoIBAGmP559B0c141pR+AJVj
-oOoBW4vueY5KMvARyLxDfdwXqN5W6QiiotIE8H4QtOCIvQu6tVftaE/X8a+L9Y/h
-NIppuoiuHM5B1UodYQcfwFp2uv37U5hjU0pxfcN2R7lq5zDURrUcgFn9Xh1lGwsd
-IRKYGqvKiAk9CwRuxwFCsWbgba9mIrSmoQUknacJxJlfgnEGtKWEbGkWvQv4O7Ii
-+sHyUGXWZLsKkV59Yh1Z4ISkhrci8VSUcpvZq5VZZSN+z+OQss7RReD+KArqV9id
-bgYp//AqA2Gq9j6uzqo4eiG+FR/euSHVPw9llIkzXwPSJYvifx9cpaTOawMGyRY2
-vdkCggEBAJECl41qbQE7OIPsSmhcz0nK6L4aIkdOxZ6hs6xO7fPwh7EntojPIB6J
-bMuvfujqW4SZ+ZpwZkCc8p8j2VuQvlXLI+s6923IdYAOK5ND9q3Xj7AqgJjUKbhH
-lpYUtfDmIjqVADoiIYXmZBPAo7QvzkX7A2qclV7VL/Dc94bBS6M+v/JGh7QyTCsO
-oPK6IOlGL1yg+CdZIzdSiJKVeESPMOBhNtPhm+vOXvRV08ECEILD1j52rUKcPs+I
-uINxopeXePgekedm7nyAW3IMHFKa4EiuEU3LQOaWeKEnaxNdOh12Pyyd6w2iAmrr
-rj/p/2CWVN8OTi7CY5cOTCadHZRyjYA=
------END PRIVATE KEY-----
diff --git a/tests/utils.py b/tests/utils.py
deleted file mode 100644
index c6c10a8..0000000
--- a/tests/utils.py
+++ /dev/null
@@ -1,78 +0,0 @@
-# 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 json
-import zipfile
-from pathlib import Path
-from typing import Any, Dict, List, Optional, Tuple, TypeVar
-
-
-def parse_trace(path: Path) -> Tuple[Dict[str, bytes], List[Any]]:
- resources: Dict[str, bytes] = {}
- with zipfile.ZipFile(path, "r") as zip:
- for name in zip.namelist():
- resources[name] = zip.read(name)
- action_map: Dict[str, Any] = {}
- events: List[Any] = []
- for name in ["trace.trace", "trace.network"]:
- for line in resources[name].decode().splitlines():
- if not line:
- continue
- event = json.loads(line)
- if event["type"] == "before":
- event["type"] = "action"
- action_map[event["callId"]] = event
- events.append(event)
- elif event["type"] == "input":
- pass
- elif event["type"] == "after":
- existing = action_map[event["callId"]]
- existing["error"] = event.get("error", None)
- else:
- events.append(event)
- return (resources, events)
-
-
-def get_trace_actions(events: List[Any]) -> List[str]:
- action_events = sorted(
- list(
- filter(
- lambda e: e["type"] == "action",
- events,
- )
- ),
- key=lambda e: e["startTime"],
- )
- return [e["apiName"] for e in action_events]
-
-
-TARGET_CLOSED_ERROR_MESSAGE = "Target page, context or browser has been closed"
-
-MustType = TypeVar("MustType")
-
-
-def must(value: Optional[MustType]) -> MustType:
- assert value
- return value
-
-
-def chromium_version_less_than(a: str, b: str) -> bool:
- left = list(map(int, a.split(".")))
- right = list(map(int, b.split(".")))
- for i in range(4):
- if left[i] > right[i]:
- return False
- if left[i] < right[i]:
- return True
- return False