Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 3 additions & 7 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ jobs:
- name: Install browsers
run: python -m playwright install
- name: Lint
uses: pre-commit/action@v2.0.0
uses: pre-commit/action@v2.0.3
- name: Generate APIs
run: bash scripts/update_api.sh
- name: Verify generated API is up to date
Expand Down Expand Up @@ -126,10 +126,6 @@ jobs:
browser-channel: msedge
runs-on: ${{ matrix.os }}
steps:
- name: Install Media Pack
if: matrix.os == 'windows-latest'
shell: powershell
run: Install-WindowsFeature Server-Media-Foundation
- uses: actions/checkout@v2
- name: Set up Python
uses: actions/setup-python@v2
Expand All @@ -142,8 +138,8 @@ jobs:
pip install -e .
python setup.py bdist_wheel
python -m playwright install-deps
- name: Install ffmpeg
run: python -m playwright install ffmpeg
- name: Install browsers
run: python -m playwright install ${{ matrix.browser-channel }}
- name: Common Tests
run: pytest tests/common --browser=chromium --browser-channel=${{ matrix.browser-channel }} --timeout 90
- name: Test Sync API
Expand Down
25 changes: 0 additions & 25 deletions playwright/_impl/_connection.py
Original file line number Diff line number Diff line change
Expand Up @@ -99,31 +99,6 @@ def __init__(
if self._parent:
self._parent._objects[guid] = self

def _wait_for_event_info_before(self, wait_id: str, api_name: str) -> None:
self._connection._send_message_to_server(
self._guid,
"waitForEventInfo",
{
"info": {
"apiName": api_name,
"waitId": wait_id,
"phase": "before",
}
},
)

def _wait_for_event_info_after(
self, wait_id: str, exception: Exception = None
) -> None:
info = {"waitId": wait_id, "phase": "after"}
if exception:
info["error"] = str(exception)
self._connection._send_message_to_server(
self._guid,
"waitForEventInfo",
{"info": info},
)

def _dispose(self) -> None:
# Clean up from parent and connection.
if self._parent:
Expand Down
2 changes: 1 addition & 1 deletion playwright/_impl/_frame.py
Original file line number Diff line number Diff line change
Expand Up @@ -122,7 +122,7 @@ async def goto(
def _setup_navigation_wait_helper(
self, wait_name: str, timeout: float = None
) -> WaitHelper:
wait_helper = WaitHelper(self, f"frame.{wait_name}")
wait_helper = WaitHelper(self._page, f"frame.{wait_name}")
wait_helper.reject_on_event(
self._page, "close", Error("Navigation failed because page was closed!")
)
Expand Down
37 changes: 32 additions & 5 deletions playwright/_impl/_wait_helper.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,14 +24,41 @@


class WaitHelper:
def __init__(self, channel_owner: ChannelOwner, api_name: str) -> None:
def __init__(self, channel_owner: ChannelOwner, event: str) -> None:
self._result: asyncio.Future = asyncio.Future()
self._wait_id = uuid.uuid4().hex
self._loop = channel_owner._loop
self._pending_tasks: List[Task] = []
self._channel_owner = channel_owner
self._channel = channel_owner._channel
self._registered_listeners: List[Tuple[EventEmitter, str, Callable]] = []
channel_owner._wait_for_event_info_before(self._wait_id, api_name)
self._wait_for_event_info_before(self._wait_id, event)

def _wait_for_event_info_before(self, wait_id: str, event: str) -> None:
self._channel.send_no_reply(
"waitForEventInfo",
{
"info": {
"waitId": wait_id,
"phase": "before",
"event": event,
}
},
)

def _wait_for_event_info_after(self, wait_id: str, error: Exception = None) -> None:
try:
Copy link
Copy Markdown
Contributor

@kumaraditya303 kumaraditya303 Jul 28, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

When / how does this raise an Exception here that you need try here ?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The page or Playwright can be closed.

self._channel.send_no_reply(
"waitForEventInfo",
{
"info": {
"waitId": wait_id,
"phase": "after",
"error": str(error) if error else None,
}
},
)
except Exception:
pass

def reject_on_event(
self,
Expand Down Expand Up @@ -68,13 +95,13 @@ def _fulfill(self, result: Any) -> None:
self._cleanup()
if not self._result.done():
self._result.set_result(result)
self._channel_owner._wait_for_event_info_after(self._wait_id)
self._wait_for_event_info_after(self._wait_id)

def _reject(self, exception: Exception) -> None:
self._cleanup()
if not self._result.done():
self._result.set_exception(exception)
self._channel_owner._wait_for_event_info_after(self._wait_id, exception)
self._wait_for_event_info_after(self._wait_id, exception)

def wait_for_event(
self,
Expand Down
1 change: 1 addition & 0 deletions tests/assets/networkidle.html
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
<script src='networkidle.js'></script>
12 changes: 12 additions & 0 deletions tests/assets/networkidle.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
async function main() {
window.ws = new WebSocket('ws://localhost:' + window.location.port + '/ws');
window.ws.addEventListener('message', message => {});

fetch('fetch-request-a.js');
window.top.fetchSecond = () => {
// Do not return the promise here.
fetch('fetch-request-b.js');
};
}

main();
79 changes: 27 additions & 52 deletions tests/async/test_accessibility.py
Original file line number Diff line number Diff line change
Expand Up @@ -221,29 +221,17 @@ async def test_accessibility_filtering_children_of_leaf_nodes_rich_text_editable
"children": [{"role": "text", "name": "my fake image"}],
}
else:
if browser_channel:
golden = {
"role": "textbox",
"name": "",
"value": "Edit this image: ",
"children": [
{"role": "text", "name": "Edit this image:"},
{"role": "img", "name": "my fake image"},
],
"value": "Edit this image: ",
}
else:
golden = {
"role": "textbox",
"name": "",
"multiline": True,
"value": "Edit this image: ",
"children": [
{"role": "text", "name": "Edit this image:"},
{"role": "img", "name": "my fake image"},
],
"value": "Edit this image: ",
}
golden = {
"role": "textbox",
"name": "",
"multiline": True,
"value": "Edit this image: ",
"children": [
{"role": "text", "name": "Edit this image:"},
{"role": "img", "name": "my fake image"},
],
"value": "Edit this image: ",
}
snapshot = await page.accessibility.snapshot()
assert snapshot["children"][0] == golden

Expand All @@ -259,19 +247,12 @@ async def test_accessibility_plain_text_field_with_role_should_not_have_children
<div contenteditable="plaintext-only" role='textbox'>Edit this image:<img src="fakeimage.png" alt="my fake image"></div>"""
)
snapshot = await page.accessibility.snapshot()
if browser_channel:
assert snapshot["children"][0] == {
"name": "",
"role": "textbox",
"value": "Edit this image:",
}
else:
assert snapshot["children"][0] == {
"multiline": True,
"name": "",
"role": "textbox",
"value": "Edit this image:",
}
assert snapshot["children"][0] == {
"multiline": True,
"name": "",
"role": "textbox",
"value": "Edit this image:",
}


@pytest.mark.only_browser("chromium")
Expand All @@ -283,14 +264,11 @@ async def test_accessibility_plain_text_field_without_role_should_not_have_conte
<div contenteditable="plaintext-only">Edit this image:<img src="fakeimage.png" alt="my fake image"></div>"""
)
snapshot = await page.accessibility.snapshot()
if browser_channel:
assert snapshot["children"][0] == {"name": "", "role": "generic"}
else:
assert snapshot["children"][0] == {
"name": "",
"role": "generic",
"value": "Edit this image:",
}
assert snapshot["children"][0] == {
"name": "",
"role": "generic",
"value": "Edit this image:",
}


@pytest.mark.only_browser("chromium")
Expand All @@ -302,14 +280,11 @@ async def test_accessibility_plain_text_field_with_tabindex_and_without_role_sho
<div contenteditable="plaintext-only" tabIndex=0>Edit this image:<img src="fakeimage.png" alt="my fake image"></div>"""
)
snapshot = await page.accessibility.snapshot()
if browser_channel:
assert snapshot["children"][0] == {"name": "", "role": "generic"}
else:
assert snapshot["children"][0] == {
"name": "",
"role": "generic",
"value": "Edit this image:",
}
assert snapshot["children"][0] == {
"name": "",
"role": "generic",
"value": "Edit this image:",
}


async def test_accessibility_non_editable_textbox_with_role_and_tabIndex_and_label_should_not_have_children(
Expand Down
11 changes: 10 additions & 1 deletion tests/async/test_navigation.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,8 @@

import pytest

from playwright.async_api import Error, Request, TimeoutError
from playwright.async_api import Error, Page, Request, TimeoutError
from tests.server import Server


async def test_goto_should_work(page, server):
Expand Down Expand Up @@ -676,6 +677,14 @@ def handler(request: Any):
await page.wait_for_load_state("domcontentloaded")


async def test_wait_for_load_state_networkidle(page: Page, server: Server):
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, context, server
):
Expand Down
79 changes: 27 additions & 52 deletions tests/sync/test_accessibility.py
Original file line number Diff line number Diff line change
Expand Up @@ -215,29 +215,17 @@ def test_accessibility_filtering_children_of_leaf_nodes_rich_text_editable_field
"children": [{"role": "text", "name": "my fake image"}],
}
else:
if browser_channel:
golden = {
"role": "textbox",
"name": "",
"value": "Edit this image: ",
"children": [
{"role": "text", "name": "Edit this image:"},
{"role": "img", "name": "my fake image"},
],
"value": "Edit this image: ",
}
else:
golden = {
"role": "textbox",
"name": "",
"multiline": True,
"value": "Edit this image: ",
"children": [
{"role": "text", "name": "Edit this image:"},
{"role": "img", "name": "my fake image"},
],
"value": "Edit this image: ",
}
golden = {
"role": "textbox",
"name": "",
"multiline": True,
"value": "Edit this image: ",
"children": [
{"role": "text", "name": "Edit this image:"},
{"role": "img", "name": "my fake image"},
],
"value": "Edit this image: ",
}
snapshot = page.accessibility.snapshot()
assert snapshot["children"][0] == golden

Expand All @@ -253,19 +241,12 @@ def test_accessibility_plain_text_field_with_role_should_not_have_children(
<div contenteditable="plaintext-only" role='textbox'>Edit this image:<img src="fakeimage.png" alt="my fake image"></div>"""
)
snapshot = page.accessibility.snapshot()
if browser_channel:
assert snapshot["children"][0] == {
"name": "",
"role": "textbox",
"value": "Edit this image:",
}
else:
assert snapshot["children"][0] == {
"multiline": True,
"name": "",
"role": "textbox",
"value": "Edit this image:",
}
assert snapshot["children"][0] == {
"multiline": True,
"name": "",
"role": "textbox",
"value": "Edit this image:",
}


@pytest.mark.only_browser("chromium")
Expand All @@ -277,14 +258,11 @@ def test_accessibility_plain_text_field_without_role_should_not_have_content(
<div contenteditable="plaintext-only">Edit this image:<img src="fakeimage.png" alt="my fake image"></div>"""
)
snapshot = page.accessibility.snapshot()
if browser_channel:
assert snapshot["children"][0] == {"name": "", "role": "generic"}
else:
assert snapshot["children"][0] == {
"name": "",
"role": "generic",
"value": "Edit this image:",
}
assert snapshot["children"][0] == {
"name": "",
"role": "generic",
"value": "Edit this image:",
}


@pytest.mark.only_browser("chromium")
Expand All @@ -296,14 +274,11 @@ def test_accessibility_plain_text_field_with_tabindex_and_without_role_should_no
<div contenteditable="plaintext-only" tabIndex=0>Edit this image:<img src="fakeimage.png" alt="my fake image"></div>"""
)
snapshot = page.accessibility.snapshot()
if browser_channel:
assert snapshot["children"][0] == {"name": "", "role": "generic"}
else:
assert snapshot["children"][0] == {
"name": "",
"role": "generic",
"value": "Edit this image:",
}
assert snapshot["children"][0] == {
"name": "",
"role": "generic",
"value": "Edit this image:",
}


def test_accessibility_non_editable_textbox_with_role_and_tabIndex_and_label_should_not_have_children(
Expand Down