@@ -64,4 +64,196 @@ public void hasPlus() throws Exception {
6464 final ChildSelector conditionChildSelector = (ChildSelector ) conditionRelativeSelector .getSelector ();
6565 assertEquals ("div#topic > *#reference" , conditionChildSelector .toString ());
6666 }
67+
68+ /**
69+ * @throws Exception if any error occurs
70+ */
71+ @ Test
72+ public void basic () throws Exception {
73+ parseSelectors ("div:has(p)" , 0 , 0 , 0 );
74+ parseSelectors ("section:has(h1)" , 0 , 0 , 0 );
75+ parseSelectors ("article:has(img)" , 0 , 0 , 0 );
76+ parseSelectors ("form:has(input)" , 0 , 0 , 0 );
77+ parseSelectors ("ul:has(li)" , 0 , 0 , 0 );
78+
79+ parseSelectors ("div:has(.warning)" , 0 , 0 , 0 );
80+ parseSelectors ("section:has(#main-title)" , 0 , 0 , 0 );
81+ parseSelectors ("article:has(.featured)" , 0 , 0 , 0 );
82+ parseSelectors ("container:has(#sidebar)" , 0 , 0 , 0 );
83+ }
84+
85+ // /* VALID CASES - Attribute selectors within :has() */
86+ // form:has(input[required]) { border: 2px solid red; }
87+ // div:has([data-active]) { opacity: 1; }
88+ // section:has(a[href^="https"]) { padding-left: 20px; }
89+ // article:has(img[alt]) { margin: 10px; }
90+ // fieldset:has(input[type="checkbox"]) { background: #e8f4fd; }
91+ //
92+ // /* VALID CASES - Pseudo-class selectors within :has() */
93+ // div:has(a:hover) { background: lightblue; }
94+ // form:has(input:focus) { box-shadow: 0 0 5px blue; }
95+ // ul:has(li:first-child) { margin-top: 0; }
96+ // table:has(tr:nth-child(odd)) { border: 1px solid; }
97+ // section:has(p:empty) { min-height: 100px; }
98+ //
99+ // /* VALID CASES - Combinators within :has() */
100+ // div:has(> p) { padding: 10px; } /* Direct child */
101+ // section:has(h1 + p) { margin: 20px; } /* Adjacent sibling */
102+ // article:has(h2 ~ p) { line-height: 1.5; } /* General sibling */
103+ // container:has(nav a) { position: relative; } /* Descendant */
104+ //
105+ // /* VALID CASES - Multiple selectors in :has() */
106+ // div:has(p, span) { color: blue; }
107+ // section:has(h1, h2, h3) { font-weight: bold; }
108+ // article:has(img, video, iframe) { max-width: 100%; }
109+ // form:has(input, textarea, select) { padding: 15px; }
110+ //
111+ // /* VALID CASES - Nested :has() selectors */
112+ // div:has(section:has(p)) { border: 2px dashed green; }
113+ // article:has(div:has(img)) { background: lightgray; }
114+ // container:has(nav:has(ul:has(li))) { position: sticky; }
115+ //
116+ // /* VALID CASES - :has() with other pseudo-classes */
117+ // div:hover:has(p) { transform: scale(1.02); }
118+ // section:focus:has(input) { outline: 2px solid blue; }
119+ // article:first-child:has(h1) { margin-top: 0; }
120+ // li:last-child:has(a) { border-bottom: none; }
121+ //
122+ // /* VALID CASES - Complex combinators with :has() */
123+ // main > section:has(aside) { display: grid; }
124+ // nav + div:has(ul) { margin-top: 10px; }
125+ // header ~ main:has(article) { padding-top: 20px; }
126+ // .sidebar div:has(.widget) { background: white; }
127+ //
128+ // /* VALID CASES - :has() with :not() */
129+ // div:has(:not(p)) { color: red; }
130+ // section:has(h1:not(.hidden)) { display: block; }
131+ // article:has(img:not([alt])) { border: 1px solid red; }
132+ // form:has(input:not(:disabled)) { opacity: 1; }
133+ //
134+ // /* VALID CASES - :has() with :is() */
135+ // div:has(:is(p, span)) { margin: 10px; }
136+ // section:has(:is(h1, h2):not(.subtitle)) { padding: 15px; }
137+ // article:has(:is(img, video)[src]) { position: relative; }
138+ //
139+ // /* VALID CASES - Whitespace variations */
140+ // div:has(p) { color: red; }
141+ // div:has( p ) { color: blue; }
142+ // div:has(
143+ // p
144+ // ) { color: green; }
145+ // div :has(p) { color: purple; } /* Space before :has() - different meaning */
146+ //
147+ // /* VALID CASES - Single and empty selectors */
148+ // div:has(span) { display: block; }
149+ // section:has(*) { border: 1px solid; } /* Has any child */
150+ //
151+ // /* EDGE CASES - Complex attribute selectors */
152+ // div:has([data-value*="test"]) { background: yellow; }
153+ // section:has([class~="active"]) { color: green; }
154+ // article:has([id|="section"]) { margin: 20px; }
155+ // form:has([name$="email"]) { border: 1px solid blue; }
156+ //
157+ // /* EDGE CASES - Escaped characters */
158+ // div:has(.class\:name) { color: red; }
159+ // section:has(#id\.special) { background: blue; }
160+ // article:has([data-test\=value]) { padding: 10px; }
161+ //
162+ // /* EDGE CASES - Unicode selectors */
163+ // div:has(.class-über) { font-family: serif; }
164+ // section:has([data-测试]) { color: red; }
165+ // article:has(.🎉) { animation: bounce 1s; }
166+ //
167+ // /* INVALID CASES - Empty :has() */
168+ // div:has() { color: red; } /* Invalid - empty selector */
169+ // section:has( ) { color: blue; } /* Invalid - whitespace only */
170+ // article:has(,) { color: green; } /* Invalid - empty selectors */
171+ //
172+ // /* INVALID CASES - Pseudo-elements inside :has() */
173+ // div:has(p::before) { color: red; } /* Invalid - pseudo-elements not allowed */
174+ // section:has(::first-line) { background: blue; } /* Invalid */
175+ // article:has(span::after) { margin: 10px; } /* Invalid */
176+ //
177+ // /* INVALID CASES - Nested :has() with pseudo-elements */
178+ // div:has(p:has(::before)) { color: red; } /* Invalid - pseudo-elements in nested :has() */
179+ //
180+ // /* INVALID CASES - :has() inside :has() with invalid selectors */
181+ // div:has(:has()) { color: red; } /* Invalid - empty nested :has() */
182+ // section:has(p:has(::after)) { background: blue; } /* Invalid - pseudo-element in nested :has() */
183+ //
184+ // /* INVALID CASES - Syntax errors */
185+ // div:has(p { color: red; } /* Invalid - missing closing parenthesis */
186+ // section:has p) { color: blue; } /* Invalid - missing opening parenthesis */
187+ // article has(p) { color: green; } /* Invalid - missing colon */
188+ // div:has[p] { color: yellow; } /* Invalid - wrong brackets */
189+ // section:has((p)) { color: purple; } /* Invalid - double parentheses */
190+ //
191+ // /* INVALID CASES - Malformed selectors within :has() */
192+ // div:has(123) { color: red; } /* Invalid - selector starting with number */
193+ // section:has(.class--) { color: blue; } /* Invalid - malformed class name */
194+ // article:has(#) { color: green; } /* Invalid - empty ID */
195+ // form:has([=value]) { color: yellow; } /* Invalid - missing attribute name */
196+ //
197+ // /* COMPLEX VALID CASES */
198+ // .container:has(.sidebar):has(.main-content) { display: grid; grid-template-columns: 1fr 3fr; }
199+ // article:has(h1):has(p):not(:has(img)) { font-family: serif; }
200+ // section:has(> div:first-child:has(h2)) { margin-top: 2rem; }
201+ // form:has(fieldset:has(legend):has(input[required])) { border: 2px solid red; }
202+ //
203+ // /* PERFORMANCE TEST CASES - Deeply nested */
204+ // div:has(div:has(div:has(div:has(p)))) { color: red; }
205+ // section:has(article:has(header:has(h1:has(span)))) { background: lightblue; }
206+ //
207+ // /* EDGE CASES - :has() with various combinators */
208+ // main:has(> section > article) { padding: 20px; }
209+ // nav:has(ul + div) { position: relative; }
210+ // aside:has(h3 ~ p ~ div) { border-left: 3px solid; }
211+ //
212+ // /* EDGE CASES - Comments within :has() */
213+ // div:has(p /* comment */) { color: red; }
214+ // section:has(/* comment */ h1) { background: blue; }
215+ //
216+ // /* EDGE CASES - Very long selector lists in :has() */
217+ // div:has(h1, h2, h3, h4, h5, h6, p, span, div, section, article, aside, header, footer, nav, main) { font-size: 14px; }
218+ //
219+ // /* EDGE CASES - Case sensitivity */
220+ // DIV:has(P) { color: red; } /* Valid - CSS is case-insensitive for HTML elements */
221+ // div:HAS(p) { color: blue; } /* Invalid - pseudo-classes are case-sensitive */
222+ //
223+ // /* EDGE CASES - Specificity testing */
224+ // div:has(p) { color: red; } /* Specificity: 0,1,1 */
225+ // div.container:has(p.content) { color: blue; } /* Specificity: 0,2,2 */
226+ // #main div:has(p) { color: green; } /* Specificity: 1,1,1 */
227+ //
228+ // /* EDGE CASES - Multiple :has() selectors */
229+ // div:has(p):has(span) { background: yellow; }
230+ // section:has(h1):has(img):has(a) { border: 1px solid; }
231+ // article:has(.title):has(.content):has(.footer) { margin: 20px; }
232+ //
233+ // /* EDGE CASES - :has() with :where() (low specificity) */
234+ // :where(div):has(p) { color: red; }
235+ // div:has(:where(p, span)) { background: blue; }
236+ //
237+ // /* BROWSER COMPATIBILITY - Older syntax (for comparison) */
238+ // /* Note: :has() is relatively new, no legacy equivalents exist */
239+ //
240+ // /* STRESS TESTS - Complex realistic scenarios */
241+ // .card:has(.card-header):has(.card-body):not(:has(.card-footer)) {
242+ // border-bottom: 2px solid #ccc;
243+ // }
244+ //
245+ // .form-group:has(input[required]):has(label):not(:has(.error)) {
246+ // border-left: 3px solid green;
247+ // }
248+ //
249+ // .navigation:has(ul:has(li:has(a[href^="#"]))):has(.dropdown) {
250+ // position: sticky;
251+ // top: 0;
252+ // }
253+ //
254+ // /* EDGE CASES - :has() at different positions */
255+ // :has(p) div { color: red; } /* Invalid - :has() must be preceded by a selector */
256+ // *:has(p) { color: blue; } /* Valid - universal selector with :has() */
257+ // :root:has(body) { font-size: 16px; } /* Valid but unusual */
258+
67259}
0 commit comments