@@ -145,6 +145,10 @@ def parse_many(first, *others):
145145 'Hash[Element[div]#foobar]' ]
146146 assert parse_many ('div:not(div.foo)' ) == [
147147 'Negation[Element[div]:not(Class[Element[div].foo])]' ]
148+ assert parse_many ('div:is(.foo, #bar)' ) == [
149+ 'Matching[Element[div]:is(Class[Element[*].foo], Hash[Element[*]#bar])]' ]
150+ assert parse_many (':is(:hover, :visited)' ) == [
151+ 'Matching[Element[*]:is(Pseudo[Element[*]:hover], Pseudo[Element[*]:visited])]' ]
148152 assert parse_many ('td ~ th' ) == [
149153 'CombinedSelector[Element[td] ~ Element[th]]' ]
150154 assert parse_many (':scope > foo' ) == [
@@ -270,6 +274,8 @@ def specificity(css):
270274 assert specificity (':has(foo)' ) == (0 , 0 , 1 )
271275 assert specificity (':has(> foo)' ) == (0 , 0 , 1 )
272276
277+ assert specificity (':is(.foo, #bar)' ) == (1 , 0 , 0 )
278+ assert specificity (':is(:hover, :visited)' ) == (0 , 1 , 0 )
273279
274280 assert specificity ('foo:empty' ) == (0 , 1 , 1 )
275281 assert specificity ('foo:before' ) == (0 , 0 , 2 )
@@ -311,6 +317,8 @@ def css2css(css, res=None):
311317 # css2css(':has(*[foo])', ':has([foo])')
312318 # css2css(':has(:empty)')
313319 # css2css(':has(#foo)')
320+ css2css (':is(#bar, .foo)' )
321+ css2css (':is(:focused, :visited)' )
314322 css2css ('foo:empty' )
315323 css2css ('foo::before' )
316324 css2css ('foo:empty::before' )
@@ -384,6 +392,10 @@ def get_error(css):
384392 "Got pseudo-element ::before inside :not() at 12" )
385393 assert get_error (':not(:not(a))' ) == (
386394 "Got nested :not()" )
395+ assert get_error (':is(:before)' ) == (
396+ "Got pseudo-element ::before inside function" )
397+ assert get_error (':is(a b)' ) == (
398+ "Expected an argument, got <IDENT 'b' at 6>" )
387399 assert get_error (':scope > div :scope header' ) == (
388400 'Got immediate child pseudo-element ":scope" not at the start of a selector'
389401 )
@@ -502,7 +514,7 @@ def xpath(css):
502514 assert xpath ('e:not(:nth-child(odd))' ) == (
503515 "e[not(count(preceding-sibling::*) mod 2 = 0)]" )
504516 assert xpath ('e:nOT(*)' ) == (
505- "e[0]" ) # never matches
517+ "e[0]" ) # never matches
506518 assert xpath ('e:has(> f)' ) == 'e[./f]'
507519 assert xpath ('e:has(f)' ) == 'e/descendant-or-self::f/ancestor-or-self::e'
508520 assert xpath ('e:has(~ f)' ) == 'e/following-sibling::f/preceding-sibling::e'
@@ -881,6 +893,12 @@ def pcss(main, *selectors, **kwargs):
881893 # assert pcss('link:has(*)') == []
882894 # assert pcss('link:has([href])') == ['link-href']
883895 # assert pcss('ol:has(div)') == ['first-ol']
896+ assert pcss (':is(#first-li, #second-li)' ) == [
897+ 'first-li' , 'second-li' ]
898+ assert pcss ('a:is(#name-anchor, #tag-anchor)' ) == [
899+ 'name-anchor' , 'tag-anchor' ]
900+ assert pcss (':is(.c)' ) == [
901+ 'first-ol' , 'third-li' , 'fourth-li' ]
884902 assert pcss ('ol.a.b.c > li.c:nth-child(3)' ) == ['third-li' ]
885903
886904 # Invalid characters in XPath element names, should not crash
0 commit comments