Skip to content

Commit bd6820d

Browse files
committed
fixed tests
1 parent a3faf15 commit bd6820d

File tree

8 files changed

+206
-36
lines changed

8 files changed

+206
-36
lines changed

local-requirements.txt

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,9 @@ pixelmatch==0.2.3
1111
pre-commit==2.10.1
1212
pyOpenSSL==20.0.1
1313
pytest==6.2.2
14-
pytest-asyncio==0.14.0
14+
pytest-asyncio==0.15.0
1515
pytest-cov==2.11.1
16+
pytest-repeat==0.9.1
1617
pytest-sugar==0.9.4
1718
pytest-timeout==1.4.2
1819
pytest-xdist==2.2.1

playwright/_impl/_browser_type.py

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -141,17 +141,29 @@ async def connect(
141141
) -> Browser:
142142
transport = WebSocketTransport(ws_endpoint, timeout)
143143

144-
connection = Connection(None, self._connection._object_factory, transport)
144+
connection = Connection(
145+
self._connection._dispatcher_fiber,
146+
self._connection._object_factory,
147+
transport,
148+
)
145149
connection._loop = self._connection._loop
146150
connection._loop.create_task(connection.run())
151+
self._connection._child_ws_connections.append(connection)
147152
playwright = await connection.wait_for_object_with_known_name("Playwright")
148153
pre_launched_browser = playwright._initializer.get("preLaunchedBrowser")
149154
assert pre_launched_browser
150155
browser = cast(Browser, from_channel(pre_launched_browser))
151156
browser._is_remote = True
152157
browser._is_connected_over_websocket = True
153158

154-
transport.on("close", browser._on_close)
159+
def handle_transport_close() -> None:
160+
browser._on_close()
161+
162+
transport.on("close", handle_transport_close)
163+
browser.once(
164+
Browser.Events.Disconnected,
165+
lambda b: transport.remove_listener("close", handle_transport_close),
166+
)
155167

156168
return browser
157169

playwright/_impl/_connection.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -163,6 +163,7 @@ def __init__(
163163
self._object_factory = object_factory
164164
self._is_sync = False
165165
self._api_name = ""
166+
self._child_ws_connections: List["Connection"] = []
166167

167168
async def run_as_sync(self) -> None:
168169
self._is_sync = True
@@ -176,10 +177,16 @@ async def run(self) -> None:
176177
def stop_sync(self) -> None:
177178
self._transport.stop()
178179
self._dispatcher_fiber.switch()
180+
self.cleanup()
179181

180182
async def stop_async(self) -> None:
181183
self._transport.stop()
182184
await self._transport.wait_until_stopped()
185+
self.cleanup()
186+
187+
def cleanup(self) -> None:
188+
for ws_connection in self._child_ws_connections:
189+
ws_connection._transport.cleanup()
183190

184191
async def wait_for_object_with_known_name(self, guid: str) -> Any:
185192
if guid in self._objects:

playwright/_impl/_transport.py

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -43,19 +43,21 @@ def _get_stderr_fileno() -> Optional[int]:
4343
class Transport(ABC):
4444
def __init__(self) -> None:
4545
self.on_message = lambda _: None
46-
self.on_error_future = asyncio.Future()
4746

4847
@abstractmethod
4948
def stop(self) -> None:
5049
pass
5150

51+
def cleanup(self) -> None:
52+
pass
53+
5254
@abstractmethod
5355
async def wait_until_stopped(self) -> None:
5456
pass
5557

56-
@abstractmethod
5758
async def run(self) -> None:
58-
pass
59+
self._loop = asyncio.get_running_loop()
60+
self.on_error_future: asyncio.Future[bool] = asyncio.Future()
5961

6062
@abstractmethod
6163
def send(self, message: Dict) -> None:
@@ -91,7 +93,7 @@ async def wait_until_stopped(self) -> None:
9193
await self._proc.wait()
9294

9395
async def run(self) -> None:
94-
self._loop = asyncio.get_running_loop()
96+
await super().run()
9597
self._stopped_future: asyncio.Future = asyncio.Future()
9698

9799
self._proc = proc = await asyncio.create_subprocess_exec(
@@ -148,11 +150,14 @@ def stop(self) -> None:
148150
self._stopped = True
149151
self._loop.create_task(self._connection.close())
150152

153+
def cleanup(self) -> None:
154+
self.on_error_future.cancel()
155+
151156
async def wait_until_stopped(self) -> None:
152157
await self._connection.wait_closed()
153158

154159
async def run(self) -> None:
155-
self._loop = asyncio.get_running_loop()
160+
await super().run()
156161

157162
options = {}
158163
if self.timeout is not None:
@@ -180,6 +185,6 @@ def send(self, message: Dict) -> None:
180185
data = self.serialize_message(message)
181186
self._loop.create_task(self._connection.send(data))
182187

183-
def test_if_closed(self):
188+
def test_if_closed(self) -> None:
184189
if self._stopped or self._connection.closed:
185190
raise Error("Playwright connection closed")

setup.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ def run(self) -> None:
134134
packages=["playwright"],
135135
include_package_data=True,
136136
install_requires=[
137+
"websockets>=8.1",
137138
"greenlet>=0.4",
138139
"pyee>=8.0.1",
139140
"typing-extensions;python_version<='3.8'",

tests/async/test_browsertype_connect.py

Lines changed: 12 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ async def test_browser_type_connect_should_be_able_to_reconnect_to_a_browser(
2828
browser_context = await browser.new_context()
2929
assert len(browser_context.pages) == 0
3030
page = await browser_context.new_page()
31+
assert len(browser_context.pages) == 1
3132
assert await page.evaluate("11 * 11") == 121
3233
await page.goto(server.EMPTY_PAGE)
3334
await browser.close()
@@ -40,7 +41,7 @@ async def test_browser_type_connect_should_be_able_to_reconnect_to_a_browser(
4041

4142

4243
async def test_browser_type_connect_should_be_able_to_connect_two_browsers_at_the_same_time(
43-
server: Server, browser_type: BrowserType, launch_server
44+
browser_type: BrowserType, launch_server
4445
):
4546
remote_server = launch_server()
4647
browser1 = await browser_type.connect(remote_server.ws_endpoint)
@@ -63,7 +64,7 @@ async def test_browser_type_connect_should_be_able_to_connect_two_browsers_at_th
6364

6465

6566
async def test_browser_type_connect_disconnected_event_should_be_emitted_when_browser_is_closed_or_server_is_closed(
66-
server: Server, browser_type: BrowserType, launch_server
67+
browser_type: BrowserType, launch_server
6768
):
6869
# Launch another server to not affect other tests.
6970
remote = launch_server()
@@ -72,27 +73,27 @@ async def test_browser_type_connect_disconnected_event_should_be_emitted_when_br
7273
browser2 = await browser_type.connect(remote.ws_endpoint)
7374

7475
disconnected1 = []
75-
disconnected2_event_future: asyncio.Future[bool] = asyncio.Future()
76+
disconnected2 = []
7677
browser1.on("disconnected", lambda: disconnected1.append(True))
77-
browser2.on("disconnected", lambda: disconnected2_event_future.set_result(True))
78+
browser2.on("disconnected", lambda: disconnected2.append(True))
7879

7980
page2 = await browser2.new_page()
8081

8182
await browser1.close()
8283
assert len(disconnected1) == 1
83-
assert disconnected2_event_future.done() is False
84+
assert len(disconnected2) == 0
8485

8586
remote.kill()
8687
assert len(disconnected1) == 1
8788

8889
with pytest.raises(Error):
8990
# Tickle connection so that it gets a chance to dispatch disconnect event.
9091
await page2.title()
91-
await disconnected2_event_future
92+
assert len(disconnected2) == 1
9293

9394

9495
async def test_browser_type_disconnected_event_should_have_browser_as_argument(
95-
server: Server, browser_type: BrowserType, launch_server
96+
browser_type: BrowserType, launch_server
9697
):
9798
remote_server = launch_server()
9899
browser = await browser_type.connect(remote_server.ws_endpoint)
@@ -103,7 +104,7 @@ async def test_browser_type_disconnected_event_should_have_browser_as_argument(
103104

104105

105106
async def test_browser_type_connect_set_browser_connected_state(
106-
server: Server, browser_type: BrowserType, launch_server
107+
browser_type: BrowserType, launch_server
107108
):
108109
remote_server = launch_server()
109110
browser = await browser_type.connect(remote_server.ws_endpoint)
@@ -113,26 +114,17 @@ async def test_browser_type_connect_set_browser_connected_state(
113114

114115

115116
async def test_browser_type_connect_should_throw_when_used_after_is_connected_returns_false(
116-
server: Server, browser_type: BrowserType, launch_server
117+
browser_type: BrowserType, launch_server
117118
):
118119
remote_server = launch_server()
119120
browser = await browser_type.connect(remote_server.ws_endpoint)
120121
page = await browser.new_page()
121122

122-
disconnected_event_future: asyncio.Future[bool] = asyncio.Future()
123-
browser.on("disconnected", lambda: disconnected_event_future.set_result(True))
124-
125123
remote_server.kill()
126124

127-
# Wait until the process and its WS connection is closed
128-
await disconnected_event_future
129-
130125
with pytest.raises(Error) as exc_info:
131126
await page.evaluate("1 + 1")
132-
assert "Protocol error (Runtime.evaluate): Target closed." in exc_info.value.message
133-
on_disconnected: asyncio.Future[None] = asyncio.Future()
134-
browser.on("disconnected", lambda: on_disconnected.set_result(None))
135-
await on_disconnected
127+
assert "Playwright connection closed" == exc_info.value.message
136128
assert browser.is_connected() is False
137129

138130

@@ -142,7 +134,7 @@ async def test_browser_type_connect_should_reject_navigation_when_browser_closes
142134
remote_server = launch_server()
143135
browser = await browser_type.connect(remote_server.ws_endpoint)
144136
page = await browser.new_page()
145-
server.set_route("/one-style.css", lambda: None)
137+
server.set_route("/one-style.css", lambda r: None)
146138
page.on("request", lambda: asyncio.create_task(browser.close()))
147139

148140
with pytest.raises(Error) as exc_info:

tests/conftest.py

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,18 @@
1313
# limitations under the License.
1414

1515
import asyncio
16+
import inspect
1617
import io
17-
import os
18-
import signal
1918
import subprocess
2019
import sys
20+
from pathlib import Path
2121

2222
import pytest
2323
from PIL import Image
2424
from pixelmatch import pixelmatch
2525
from pixelmatch.contrib.PIL import from_PIL_to_raw_data
2626

27-
from playwright._impl._driver import compute_driver_executable
27+
import playwright
2828
from playwright._impl._path_utils import get_file_dirname
2929

3030
from .server import test_server
@@ -208,17 +208,28 @@ def compare(received_raw: bytes, golden_name: str):
208208

209209
class RemoteServer:
210210
def __init__(self, browser_name: str) -> None:
211-
self.process = subprocess.Popen(
212-
[compute_driver_executable(), "launch-server", browser_name],
211+
driver_dir = Path(inspect.getfile(playwright)).parent / "driver"
212+
if sys.platform == "win32":
213+
node_executable = driver_dir / "node.exe"
214+
else:
215+
node_executable = driver_dir / "node"
216+
cli_js = driver_dir / "package" / "lib" / "cli" / "cli.js"
217+
self.process = subprocess.Popen( # type: ignore
218+
[str(node_executable), str(cli_js), "launch-server", browser_name],
213219
stdout=subprocess.PIPE,
214-
preexec_fn=os.setsid,
220+
stderr=sys.stderr,
221+
cwd=driver_dir,
215222
)
216223
assert self.process.stdout
217224
self.ws_endpoint = self.process.stdout.readline().decode().strip()
218225

219226
def kill(self):
220227
# Send the signal to all the process groups
221-
os.killpg(os.getpgid(self.process.pid), signal.SIGTERM)
228+
if sys.platform == "win32":
229+
subprocess.check_call(f"taskkill /F /PID {self.process.pid}")
230+
else:
231+
self.process.kill()
232+
self.process.wait()
222233

223234

224235
@pytest.fixture

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy