Skip to content

Commit 25a99d5

Browse files
authored
test: mmigrate to expect_ where possible (microsoft#428)
1 parent 39374d0 commit 25a99d5

32 files changed

+2455
-1171
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ Playwright is a Python library to automate [Chromium](https://www.chromium.org/H
88
| :--- | :---: | :---: | :---: |
99
| Chromium <!-- GEN:chromium-version -->89.0.4344.0<!-- GEN:stop --> ||||
1010
| WebKit <!-- GEN:webkit-version -->14.1<!-- GEN:stop --> ||||
11-
| Firefox <!-- GEN:firefox-version -->85.0b1<!-- GEN:stop --> ||||
11+
| Firefox <!-- GEN:firefox-version -->85.0b5<!-- GEN:stop --> ||||
1212

1313
Headless execution is supported for all browsers on all platforms.
1414

playwright/_impl/_async_base.py

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

1515
import asyncio
16-
from typing import Any, Callable, Coroutine, Generic, Optional, TypeVar, cast
16+
from typing import Any, Callable, Generic, TypeVar
1717

1818
from playwright._impl._impl_to_api_mapping import ImplToApiMapping, ImplWrapper
1919

@@ -24,22 +24,17 @@
2424

2525

2626
class AsyncEventInfo(Generic[T]):
27-
def __init__(self, coroutine: Coroutine) -> None:
28-
self._value: Optional[T] = None
29-
self._future = asyncio.get_event_loop().create_task(coroutine)
30-
self._done = False
27+
def __init__(self, future: asyncio.Future) -> None:
28+
self._future = future
3129

3230
@property
3331
async def value(self) -> T:
34-
if not self._done:
35-
self._value = mapping.from_maybe_impl(await self._future)
36-
self._done = True
37-
return cast(T, self._value)
32+
return mapping.from_maybe_impl(await self._future)
3833

3934

4035
class AsyncEventContextManager(Generic[T]):
41-
def __init__(self, coroutine: Coroutine) -> None:
42-
self._event: AsyncEventInfo = AsyncEventInfo(coroutine)
36+
def __init__(self, future: asyncio.Future) -> None:
37+
self._event: AsyncEventInfo = AsyncEventInfo(future)
4338

4439
async def __aenter__(self) -> AsyncEventInfo[T]:
4540
return self._event

playwright/_impl/_browser_context.py

Lines changed: 15 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,6 @@
2424
from playwright._impl._connection import ChannelOwner, from_channel
2525
from playwright._impl._event_context_manager import EventContextManagerImpl
2626
from playwright._impl._helper import (
27-
PendingWaitEvent,
2827
RouteHandler,
2928
RouteHandlerEntry,
3029
TimeoutSettings,
@@ -55,7 +54,6 @@ def __init__(
5554
self._pages: List[Page] = []
5655
self._routes: List[RouteHandlerEntry] = []
5756
self._bindings: Dict[str, Any] = {}
58-
self._pending_wait_for_events: List[PendingWaitEvent] = []
5957
self._timeout_settings = TimeoutSettings(None)
6058
self._browser: Optional["Browser"] = None
6159
self._owner_page: Optional[Page] = None
@@ -201,9 +199,12 @@ async def unroute(
201199
"setNetworkInterceptionEnabled", dict(enabled=False)
202200
)
203201

204-
async def wait_for_event(
205-
self, event: str, predicate: Callable = None, timeout: float = None
206-
) -> Any:
202+
def expect_event(
203+
self,
204+
event: str,
205+
predicate: Callable = None,
206+
timeout: float = None,
207+
) -> EventContextManagerImpl:
207208
if timeout is None:
208209
timeout = self._timeout_settings.timeout()
209210
wait_helper = WaitHelper(self._loop)
@@ -214,18 +215,14 @@ async def wait_for_event(
214215
wait_helper.reject_on_event(
215216
self, BrowserContext.Events.Close, Error("Context closed")
216217
)
217-
return await wait_helper.wait_for_event(self, event, predicate)
218+
wait_helper.wait_for_event(self, event, predicate)
219+
return EventContextManagerImpl(wait_helper.result())
218220

219221
def _on_close(self) -> None:
220222
self._is_closed_or_closing = True
221223
if self._browser:
222224
self._browser._contexts.remove(self)
223225

224-
for pending_event in self._pending_wait_for_events:
225-
if pending_event.event == BrowserContext.Events.Close:
226-
continue
227-
pending_event.reject(False, "Context")
228-
229226
self.emit(BrowserContext.Events.Close)
230227

231228
async def close(self) -> None:
@@ -245,17 +242,16 @@ async def storage_state(self, path: Union[str, Path] = None) -> StorageState:
245242
json.dump(result, f)
246243
return result
247244

248-
def expect_event(
249-
self,
250-
event: str,
251-
predicate: Callable = None,
252-
timeout: float = None,
253-
) -> EventContextManagerImpl:
254-
return EventContextManagerImpl(self.wait_for_event(event, predicate, timeout))
245+
async def wait_for_event(
246+
self, event: str, predicate: Callable = None, timeout: float = None
247+
) -> Any:
248+
async with self.expect_event(event, predicate, timeout) as event_info:
249+
pass
250+
return await event_info.value
255251

256252
def expect_page(
257253
self,
258254
predicate: Callable[[Page], bool] = None,
259255
timeout: float = None,
260256
) -> EventContextManagerImpl[Page]:
261-
return EventContextManagerImpl(self.wait_for_event("page", predicate, timeout))
257+
return self.expect_event(BrowserContext.Events.Page, predicate, timeout)

playwright/_impl/_event_context_manager.py

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

1515
import asyncio
16-
from typing import Any, Coroutine, Generic, Optional, TypeVar, cast
16+
from typing import Any, Generic, TypeVar
1717

1818
T = TypeVar("T")
1919

2020

2121
class EventInfoImpl(Generic[T]):
22-
def __init__(self, coroutine: Coroutine) -> None:
23-
self._value: Optional[T] = None
24-
self._task = asyncio.get_event_loop().create_task(coroutine)
25-
self._done = False
22+
def __init__(self, future: asyncio.Future) -> None:
23+
self._future = future
2624

2725
@property
2826
async def value(self) -> T:
29-
if not self._done:
30-
self._value = await self._task
31-
self._done = True
32-
return cast(T, self._value)
27+
return await self._future
3328

3429

3530
class EventContextManagerImpl(Generic[T]):
36-
def __init__(self, coroutine: Coroutine) -> None:
37-
self._event: EventInfoImpl = EventInfoImpl(coroutine)
31+
def __init__(self, future: asyncio.Future) -> None:
32+
self._event: EventInfoImpl = EventInfoImpl(future)
33+
34+
@property
35+
def future(self) -> asyncio.Future:
36+
return self._event._future
3837

3938
async def __aenter__(self) -> EventInfoImpl[T]:
4039
return self._event

playwright/_impl/_frame.py

Lines changed: 29 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -135,14 +135,14 @@ def _setup_navigation_wait_helper(self, timeout: float = None) -> WaitHelper:
135135
wait_helper.reject_on_timeout(timeout, f"Timeout {timeout}ms exceeded.")
136136
return wait_helper
137137

138-
async def wait_for_navigation(
138+
def expect_navigation(
139139
self,
140140
url: URLMatch = None,
141-
waitUntil: DocumentLoadState = None,
141+
wait_until: DocumentLoadState = None,
142142
timeout: float = None,
143-
) -> Optional[Response]:
144-
if not waitUntil:
145-
waitUntil = "load"
143+
) -> EventContextManagerImpl[Response]:
144+
if not wait_until:
145+
wait_until = "load"
146146

147147
if timeout is None:
148148
timeout = self._page._timeout_settings.navigation_timeout()
@@ -156,23 +156,26 @@ def predicate(event: Any) -> bool:
156156
return True
157157
return not matcher or matcher.matches(event["url"])
158158

159-
event = await wait_helper.wait_for_event(
159+
wait_helper.wait_for_event(
160160
self._event_emitter,
161161
"navigated",
162162
predicate=predicate,
163163
)
164-
if "error" in event:
165-
raise Error(event["error"])
166-
167-
if waitUntil not in self._load_states:
168-
t = deadline - monotonic_time()
169-
if t > 0:
170-
await self.wait_for_load_state(state=waitUntil, timeout=t)
171164

172-
if "newDocument" in event and "request" in event["newDocument"]:
173-
request = from_channel(event["newDocument"]["request"])
174-
return await request.response()
175-
return None
165+
async def continuation() -> Optional[Response]:
166+
event = await wait_helper.result()
167+
if "error" in event:
168+
raise Error(event["error"])
169+
if wait_until not in self._load_states:
170+
t = deadline - monotonic_time()
171+
if t > 0:
172+
await self.wait_for_load_state(state=wait_until, timeout=t)
173+
if "newDocument" in event and "request" in event["newDocument"]:
174+
request = from_channel(event["newDocument"]["request"])
175+
return await request.response()
176+
return None
177+
178+
return EventContextManagerImpl(asyncio.create_task(continuation()))
176179

177180
async def wait_for_load_state(
178181
self, state: DocumentLoadState = None, timeout: float = None
@@ -184,9 +187,10 @@ async def wait_for_load_state(
184187
if state in self._load_states:
185188
return
186189
wait_helper = self._setup_navigation_wait_helper(timeout)
187-
await wait_helper.wait_for_event(
190+
wait_helper.wait_for_event(
188191
self._event_emitter, "loadstate", lambda s: s == state
189192
)
193+
await wait_helper.result()
190194

191195
async def frame_element(self) -> ElementHandle:
192196
return from_channel(await self._channel.send("frameElement"))
@@ -526,12 +530,14 @@ async def wait_for_function(
526530
async def title(self) -> str:
527531
return await self._channel.send("title")
528532

529-
def expect_navigation(
533+
async def wait_for_navigation(
530534
self,
531535
url: URLMatch = None,
532536
waitUntil: DocumentLoadState = None,
533537
timeout: float = None,
534-
) -> EventContextManagerImpl:
535-
return EventContextManagerImpl(
536-
self.wait_for_navigation(url, waitUntil, timeout)
537-
)
538+
) -> Optional[Response]:
539+
async with self.expect_navigation(
540+
url, waitUntil, timeout=timeout
541+
) as response_info:
542+
pass
543+
return await response_info.value

playwright/_impl/_helper.py

Lines changed: 0 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@
1212
# See the License for the specific language governing permissions and
1313
# limitations under the License.
1414

15-
import asyncio
1615
import fnmatch
1716
import math
1817
import re
@@ -199,25 +198,6 @@ def monotonic_time() -> int:
199198
return math.floor(time.monotonic() * 1000)
200199

201200

202-
class PendingWaitEvent:
203-
def __init__(
204-
self, event: str, future: asyncio.Future, timeout_future: asyncio.Future
205-
):
206-
self.event = event
207-
self.future = future
208-
self.timeout_future = timeout_future
209-
210-
def reject(self, is_crash: bool, target: str) -> None:
211-
self.timeout_future.cancel()
212-
if self.event == "close" and not is_crash:
213-
return
214-
if self.event == "crash" and is_crash:
215-
return
216-
self.future.set_exception(
217-
Error(f"{target} crashed" if is_crash else f"{target} closed")
218-
)
219-
220-
221201
class RouteHandlerEntry:
222202
def __init__(self, matcher: URLMatcher, handler: RouteHandler):
223203
self.matcher = matcher

playwright/_impl/_network.py

Lines changed: 14 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -293,9 +293,12 @@ def __init__(
293293
def url(self) -> str:
294294
return self._initializer["url"]
295295

296-
async def wait_for_event(
297-
self, event: str, predicate: Callable = None, timeout: float = None
298-
) -> Any:
296+
def expect_event(
297+
self,
298+
event: str,
299+
predicate: Callable = None,
300+
timeout: float = None,
301+
) -> EventContextManagerImpl:
299302
if timeout is None:
300303
timeout = cast(Any, self._parent)._timeout_settings.timeout()
301304
wait_helper = WaitHelper(self._loop)
@@ -311,15 +314,15 @@ async def wait_for_event(
311314
self, WebSocket.Events.Error, Error("Socket error")
312315
)
313316
wait_helper.reject_on_event(self._parent, "close", Error("Page closed"))
314-
return await wait_helper.wait_for_event(self, event, predicate)
317+
wait_helper.wait_for_event(self, event, predicate)
318+
return EventContextManagerImpl(wait_helper.result())
315319

316-
def expect_event(
317-
self,
318-
event: str,
319-
predicate: Callable = None,
320-
timeout: float = None,
321-
) -> EventContextManagerImpl:
322-
return EventContextManagerImpl(self.wait_for_event(event, predicate, timeout))
320+
async def wait_for_event(
321+
self, event: str, predicate: Callable = None, timeout: float = None
322+
) -> Any:
323+
async with self.expect_event(event, predicate, timeout) as event_info:
324+
pass
325+
return await event_info.value
323326

324327
def _on_frame_sent(self, opcode: int, data: str) -> None:
325328
if opcode == 2:

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