@@ -73,7 +73,9 @@ def __init__(
7373 frame : "Frame" ,
7474 selector : str ,
7575 has_text : Union [str , Pattern [str ]] = None ,
76+ has_not_text : Union [str , Pattern [str ]] = None ,
7677 has : "Locator" = None ,
78+ has_not : "Locator" = None ,
7779 ) -> None :
7880 self ._frame = frame
7981 self ._selector = selector
@@ -90,6 +92,15 @@ def __init__(
9092 has ._selector , ensure_ascii = False
9193 )
9294
95+ if has_not_text :
96+ self ._selector += f" >> internal:has-not-text={ escape_for_text_selector (has_not_text , exact = False )} "
97+
98+ if has_not :
99+ locator = has_not
100+ if locator ._frame != frame :
101+ raise Error ('Inner "has_not" locator must belong to the same frame.' )
102+ self ._selector += " >> internal:has-not=" + json .dumps (locator ._selector )
103+
93104 def __repr__ (self ) -> str :
94105 return f"<Locator frame={ self ._frame !r} selector={ self ._selector !r} >"
95106
@@ -211,13 +222,17 @@ def locator(
211222 self ,
212223 selector_or_locator : Union [str , "Locator" ],
213224 has_text : Union [str , Pattern [str ]] = None ,
225+ has_not_text : Union [str , Pattern [str ]] = None ,
214226 has : "Locator" = None ,
227+ has_not : "Locator" = None ,
215228 ) -> "Locator" :
216229 if isinstance (selector_or_locator , str ):
217230 return Locator (
218231 self ._frame ,
219232 f"{ self ._selector } >> { selector_or_locator } " ,
220233 has_text = has_text ,
234+ has_not_text = has_not_text ,
235+ has_not = has_not ,
221236 has = has ,
222237 )
223238 selector_or_locator = to_impl (selector_or_locator )
@@ -227,6 +242,8 @@ def locator(
227242 self ._frame ,
228243 f"{ self ._selector } >> { selector_or_locator ._selector } " ,
229244 has_text = has_text ,
245+ has_not_text = has_not_text ,
246+ has_not = has_not ,
230247 has = has ,
231248 )
232249
@@ -317,13 +334,25 @@ def nth(self, index: int) -> "Locator":
317334 def filter (
318335 self ,
319336 has_text : Union [str , Pattern [str ]] = None ,
337+ has_not_text : Union [str , Pattern [str ]] = None ,
320338 has : "Locator" = None ,
339+ has_not : "Locator" = None ,
321340 ) -> "Locator" :
322341 return Locator (
323342 self ._frame ,
324343 self ._selector ,
325344 has_text = has_text ,
345+ has_not_text = has_not_text ,
326346 has = has ,
347+ has_not = has_not ,
348+ )
349+
350+ def or_ (self , locator : "Locator" ) -> "Locator" :
351+ if locator ._frame != self ._frame :
352+ raise Error ("Locators must belong to the same frame." )
353+ return Locator (
354+ self ._frame ,
355+ self ._selector + " >> internal:or=" + json .dumps (locator ._selector ),
327356 )
328357
329358 async def focus (self , timeout : float = None ) -> None :
@@ -677,14 +706,18 @@ def locator(
677706 self ,
678707 selector_or_locator : Union ["Locator" , str ],
679708 has_text : Union [str , Pattern [str ]] = None ,
709+ has_not_text : Union [str , Pattern [str ]] = None ,
680710 has : "Locator" = None ,
711+ has_not : "Locator" = None ,
681712 ) -> Locator :
682713 if isinstance (selector_or_locator , str ):
683714 return Locator (
684715 self ._frame ,
685716 f"{ self ._frame_selector } >> internal:control=enter-frame >> { selector_or_locator } " ,
686717 has_text = has_text ,
718+ has_not_text = has_not_text ,
687719 has = has ,
720+ has_not = has_not ,
688721 )
689722 selector_or_locator = to_impl (selector_or_locator )
690723 if selector_or_locator ._frame != self ._frame :
@@ -693,7 +726,9 @@ def locator(
693726 self ._frame ,
694727 f"{ self ._frame_selector } >> internal:control=enter-frame >> { selector_or_locator ._selector } " ,
695728 has_text = has_text ,
729+ has_not_text = has_not_text ,
696730 has = has ,
731+ has_not = has_not ,
697732 )
698733
699734 def get_by_alt_text (
0 commit comments