1212# See the License for the specific language governing permissions and
1313# limitations under the License.
1414
15+ import json
1516import pathlib
1617import sys
1718from typing import (
5354if TYPE_CHECKING : # pragma: no cover
5455 from playwright ._impl ._frame import Frame
5556 from playwright ._impl ._js_handle import JSHandle
57+ from playwright ._impl ._page import Page
5658
5759T = TypeVar ("T" )
5860
5961
6062class Locator :
6163 def __init__ (
62- self , frame : "Frame" , selector : str , has_text : Union [str , Pattern ] = None
64+ self ,
65+ frame : "Frame" ,
66+ selector : str ,
67+ has_text : Union [str , Pattern ] = None ,
68+ has : "Locator" = None ,
6369 ) -> None :
6470 self ._frame = frame
6571 self ._selector = selector
@@ -75,6 +81,11 @@ def __init__(
7581 escaped = escape_with_quotes (has_text , '"' )
7682 self ._selector += f" >> :scope:has-text({ escaped } )"
7783
84+ if has :
85+ if has ._frame != frame :
86+ raise Error ('Inner "has" locator must belong to the same frame.' )
87+ self ._selector += " >> has=" + json .dumps (has ._selector )
88+
7889 def __repr__ (self ) -> str :
7990 return f"<Locator frame={ self ._frame !r} selector={ self ._selector !r} >"
8091
@@ -96,6 +107,10 @@ async def _with_element(
96107 finally :
97108 await handle .dispose ()
98109
110+ @property
111+ def page (self ) -> "Page" :
112+ return self ._frame .page
113+
99114 async def bounding_box (self , timeout : float = None ) -> Optional [FloatRect ]:
100115 return await self ._with_element (
101116 lambda h , _ : h .bounding_box (),
@@ -184,9 +199,13 @@ def locator(
184199 self ,
185200 selector : str ,
186201 has_text : Union [str , Pattern ] = None ,
202+ has : "Locator" = None ,
187203 ) -> "Locator" :
188204 return Locator (
189- self ._frame , f"{ self ._selector } >> { selector } " , has_text = has_text
205+ self ._frame ,
206+ f"{ self ._selector } >> { selector } " ,
207+ has_text = has_text ,
208+ has = has ,
190209 )
191210
192211 def frame_locator (self , selector : str ) -> "FrameLocator" :
@@ -538,11 +557,14 @@ def __init__(self, frame: "Frame", frame_selector: str) -> None:
538557 self ._dispatcher_fiber = frame ._connection ._dispatcher_fiber
539558 self ._frame_selector = frame_selector
540559
541- def locator (self , selector : str , has_text : Union [str , Pattern ] = None ) -> Locator :
560+ def locator (
561+ self , selector : str , has_text : Union [str , Pattern ] = None , has : "Locator" = None
562+ ) -> Locator :
542563 return Locator (
543564 self ._frame ,
544565 f"{ self ._frame_selector } >> control=enter-frame >> { selector } " ,
545566 has_text = has_text ,
567+ has = has ,
546568 )
547569
548570 def frame_locator (self , selector : str ) -> "FrameLocator" :
0 commit comments