|
22 | 22 | Dict,
|
23 | 23 | List,
|
24 | 24 | Optional,
|
| 25 | + Pattern, |
25 | 26 | TypeVar,
|
26 | 27 | Union,
|
27 | 28 | )
|
|
42 | 43 | monotonic_time,
|
43 | 44 | )
|
44 | 45 | from playwright._impl._js_handle import Serializable, parse_value, serialize_argument
|
| 46 | +from playwright._impl._str_utils import escape_regex_flags, escape_with_quotes |
45 | 47 |
|
46 | 48 | if sys.version_info >= (3, 8): # pragma: no cover
|
47 | 49 | from typing import Literal
|
|
56 | 58 |
|
57 | 59 |
|
58 | 60 | class Locator:
|
59 |
| - def __init__(self, frame: "Frame", selector: str) -> None: |
| 61 | + def __init__( |
| 62 | + self, frame: "Frame", selector: str, has_text: Union[str, Pattern] = None |
| 63 | + ) -> None: |
60 | 64 | self._frame = frame
|
61 | 65 | self._selector = selector
|
62 | 66 | self._loop = frame._loop
|
63 | 67 | self._dispatcher_fiber = frame._connection._dispatcher_fiber
|
64 | 68 |
|
| 69 | + if has_text: |
| 70 | + if isinstance(has_text, Pattern): |
| 71 | + pattern = escape_with_quotes(has_text.pattern, '"') |
| 72 | + flags = escape_regex_flags(has_text) |
| 73 | + self._selector += f' >> :scope:text-matches({pattern}, "{flags}")' |
| 74 | + else: |
| 75 | + escaped = escape_with_quotes(has_text, '"') |
| 76 | + self._selector += f" >> :scope:has-text({escaped})" |
| 77 | + |
65 | 78 | def __repr__(self) -> str:
|
66 | 79 | return f"<Locator frame={self._frame!r} selector={self._selector!r}>"
|
67 | 80 |
|
@@ -170,8 +183,11 @@ async def fill(
|
170 | 183 | def locator(
|
171 | 184 | self,
|
172 | 185 | selector: str,
|
| 186 | + has_text: Union[str, Pattern] = None, |
173 | 187 | ) -> "Locator":
|
174 |
| - return Locator(self._frame, f"{self._selector} >> {selector}") |
| 188 | + return Locator( |
| 189 | + self._frame, f"{self._selector} >> {selector}", has_text=has_text |
| 190 | + ) |
175 | 191 |
|
176 | 192 | def frame_locator(self, selector: str) -> "FrameLocator":
|
177 | 193 | return FrameLocator(self._frame, self._selector + " >> " + selector)
|
@@ -208,7 +224,23 @@ async def focus(self, timeout: float = None) -> None:
|
208 | 224 | async def count(
|
209 | 225 | self,
|
210 | 226 | ) -> int:
|
211 |
| - return int(await self.evaluate_all("ee => ee.length")) |
| 227 | + return await self._frame._query_count(self._selector) |
| 228 | + |
| 229 | + async def drag_to( |
| 230 | + self, |
| 231 | + target: "Locator", |
| 232 | + force: bool = None, |
| 233 | + noWaitAfter: bool = None, |
| 234 | + timeout: float = None, |
| 235 | + trial: bool = None, |
| 236 | + sourcePosition: Position = None, |
| 237 | + targetPosition: Position = None, |
| 238 | + ) -> None: |
| 239 | + params = locals_to_params(locals()) |
| 240 | + del params["target"] |
| 241 | + return await self._frame.drag_and_drop( |
| 242 | + self._selector, target._selector, strict=True, **params |
| 243 | + ) |
212 | 244 |
|
213 | 245 | async def get_attribute(self, name: str, timeout: float = None) -> Optional[str]:
|
214 | 246 | params = locals_to_params(locals())
|
@@ -506,9 +538,11 @@ def __init__(self, frame: "Frame", frame_selector: str) -> None:
|
506 | 538 | self._dispatcher_fiber = frame._connection._dispatcher_fiber
|
507 | 539 | self._frame_selector = frame_selector
|
508 | 540 |
|
509 |
| - def locator(self, selector: str) -> Locator: |
| 541 | + def locator(self, selector: str, has_text: Union[str, Pattern] = None) -> Locator: |
510 | 542 | return Locator(
|
511 |
| - self._frame, f"{self._frame_selector} >> control=enter-frame >> {selector}" |
| 543 | + self._frame, |
| 544 | + f"{self._frame_selector} >> control=enter-frame >> {selector}", |
| 545 | + has_text=has_text, |
512 | 546 | )
|
513 | 547 |
|
514 | 548 | def frame_locator(self, selector: str) -> "FrameLocator":
|
|
0 commit comments