@@ -259,6 +259,178 @@ describe('CSS Modules', () => {
259
259
} ) ;
260
260
} ) ;
261
261
262
+ describe ( 'css-pseudo-4' , ( ) => {
263
+ it ( 'should parse pseudo-4 pseudo-classes' , ( ) => {
264
+ const parse = createParser ( {
265
+ modules : [ 'css-pseudo-4' ]
266
+ } ) ;
267
+
268
+ // Simple pseudo-classes
269
+ expect ( parse ( ':focus-visible' ) ) . toEqual (
270
+ ast . selector ( {
271
+ rules : [
272
+ ast . rule ( {
273
+ items : [ ast . pseudoClass ( { name : 'focus-visible' } ) ]
274
+ } )
275
+ ]
276
+ } )
277
+ ) ;
278
+
279
+ expect ( parse ( ':blank' ) ) . toEqual (
280
+ ast . selector ( {
281
+ rules : [
282
+ ast . rule ( {
283
+ items : [ ast . pseudoClass ( { name : 'blank' } ) ]
284
+ } )
285
+ ]
286
+ } )
287
+ ) ;
288
+
289
+ // Functional pseudo-classes
290
+ expect ( parse ( ':has(> img)' ) ) . toEqual (
291
+ ast . selector ( {
292
+ rules : [
293
+ ast . rule ( {
294
+ items : [
295
+ ast . pseudoClass ( {
296
+ name : 'has' ,
297
+ argument : ast . selector ( {
298
+ rules : [
299
+ ast . rule ( {
300
+ items : [ ast . tagName ( { name : 'img' } ) ] ,
301
+ combinator : '>'
302
+ } )
303
+ ]
304
+ } )
305
+ } )
306
+ ]
307
+ } )
308
+ ]
309
+ } )
310
+ ) ;
311
+
312
+ expect ( parse ( ':is(h1, h2, h3)' ) ) . toEqual (
313
+ ast . selector ( {
314
+ rules : [
315
+ ast . rule ( {
316
+ items : [
317
+ ast . pseudoClass ( {
318
+ name : 'is' ,
319
+ argument : ast . selector ( {
320
+ rules : [
321
+ ast . rule ( {
322
+ items : [ ast . tagName ( { name : 'h1' } ) ]
323
+ } ) ,
324
+ ast . rule ( {
325
+ items : [ ast . tagName ( { name : 'h2' } ) ]
326
+ } ) ,
327
+ ast . rule ( {
328
+ items : [ ast . tagName ( { name : 'h3' } ) ]
329
+ } )
330
+ ]
331
+ } )
332
+ } )
333
+ ]
334
+ } )
335
+ ]
336
+ } )
337
+ ) ;
338
+ } ) ;
339
+
340
+ it ( 'should parse pseudo-4 pseudo-elements' , ( ) => {
341
+ const parse = createParser ( {
342
+ modules : [ 'css-pseudo-4' ]
343
+ } ) ;
344
+
345
+ // Simple pseudo-elements
346
+ expect ( parse ( '::marker' ) ) . toEqual (
347
+ ast . selector ( {
348
+ rules : [
349
+ ast . rule ( {
350
+ items : [ ast . pseudoElement ( { name : 'marker' } ) ]
351
+ } )
352
+ ]
353
+ } )
354
+ ) ;
355
+
356
+ expect ( parse ( '::selection' ) ) . toEqual (
357
+ ast . selector ( {
358
+ rules : [
359
+ ast . rule ( {
360
+ items : [ ast . pseudoElement ( { name : 'selection' } ) ]
361
+ } )
362
+ ]
363
+ } )
364
+ ) ;
365
+
366
+ expect ( parse ( '::target-text' ) ) . toEqual (
367
+ ast . selector ( {
368
+ rules : [
369
+ ast . rule ( {
370
+ items : [ ast . pseudoElement ( { name : 'target-text' } ) ]
371
+ } )
372
+ ]
373
+ } )
374
+ ) ;
375
+
376
+ // String argument pseudo-elements
377
+ expect ( parse ( '::highlight(example)' ) ) . toEqual (
378
+ ast . selector ( {
379
+ rules : [
380
+ ast . rule ( {
381
+ items : [
382
+ ast . pseudoElement ( {
383
+ name : 'highlight' ,
384
+ argument : ast . string ( { value : 'example' } )
385
+ } )
386
+ ]
387
+ } )
388
+ ]
389
+ } )
390
+ ) ;
391
+
392
+ // Selector argument pseudo-elements
393
+ expect ( parse ( '::part(button)' ) ) . toEqual (
394
+ ast . selector ( {
395
+ rules : [
396
+ ast . rule ( {
397
+ items : [
398
+ ast . pseudoElement ( {
399
+ name : 'part' ,
400
+ argument : ast . selector ( {
401
+ rules : [
402
+ ast . rule ( {
403
+ items : [ ast . tagName ( { name : 'button' } ) ]
404
+ } )
405
+ ]
406
+ } )
407
+ } )
408
+ ]
409
+ } )
410
+ ]
411
+ } )
412
+ ) ;
413
+ } ) ;
414
+
415
+ it ( 'should reject pseudo-4 selectors when module is not enabled' , ( ) => {
416
+ const parse = createParser ( {
417
+ syntax : {
418
+ pseudoClasses : {
419
+ unknown : 'reject'
420
+ } ,
421
+ pseudoElements : {
422
+ unknown : 'reject'
423
+ }
424
+ }
425
+ } ) ;
426
+
427
+ expect ( ( ) => parse ( ':focus-visible' ) ) . toThrow ( 'Unknown pseudo-class: "focus-visible".' ) ;
428
+ expect ( ( ) => parse ( ':has(> img)' ) ) . toThrow ( 'Unknown pseudo-class: "has".' ) ;
429
+ expect ( ( ) => parse ( '::marker' ) ) . toThrow ( 'Unknown pseudo-element "marker".' ) ;
430
+ expect ( ( ) => parse ( '::highlight(example)' ) ) . toThrow ( 'Unknown pseudo-element "highlight".' ) ;
431
+ } ) ;
432
+ } ) ;
433
+
262
434
describe ( 'Multiple modules' , ( ) => {
263
435
it ( 'should support multiple modules at once' , ( ) => {
264
436
const parse = createParser ( {
@@ -309,5 +481,72 @@ describe('CSS Modules', () => {
309
481
} )
310
482
) ;
311
483
} ) ;
484
+
485
+ it ( 'should support combining css-position and css-pseudo modules' , ( ) => {
486
+ const parse = createParser ( {
487
+ modules : [ 'css-position-3' , 'css-pseudo-4' ]
488
+ } ) ;
489
+
490
+ // Position pseudo-class
491
+ expect ( parse ( ':sticky' ) ) . toEqual (
492
+ ast . selector ( {
493
+ rules : [
494
+ ast . rule ( {
495
+ items : [ ast . pseudoClass ( { name : 'sticky' } ) ]
496
+ } )
497
+ ]
498
+ } )
499
+ ) ;
500
+
501
+ // Pseudo-4 pseudo-class
502
+ expect ( parse ( ':focus-visible' ) ) . toEqual (
503
+ ast . selector ( {
504
+ rules : [
505
+ ast . rule ( {
506
+ items : [ ast . pseudoClass ( { name : 'focus-visible' } ) ]
507
+ } )
508
+ ]
509
+ } )
510
+ ) ;
511
+
512
+ // Pseudo-4 pseudo-element
513
+ expect ( parse ( '::marker' ) ) . toEqual (
514
+ ast . selector ( {
515
+ rules : [
516
+ ast . rule ( {
517
+ items : [ ast . pseudoElement ( { name : 'marker' } ) ]
518
+ } )
519
+ ]
520
+ } )
521
+ ) ;
522
+
523
+ // Complex selector using both modules
524
+ expect ( parse ( 'div:sticky:has(> img::marker)' ) ) . toEqual (
525
+ ast . selector ( {
526
+ rules : [
527
+ ast . rule ( {
528
+ items : [
529
+ ast . tagName ( { name : 'div' } ) ,
530
+ ast . pseudoClass ( { name : 'sticky' } ) ,
531
+ ast . pseudoClass ( {
532
+ name : 'has' ,
533
+ argument : ast . selector ( {
534
+ rules : [
535
+ ast . rule ( {
536
+ items : [
537
+ ast . tagName ( { name : 'img' } ) ,
538
+ ast . pseudoElement ( { name : 'marker' } )
539
+ ] ,
540
+ combinator : '>'
541
+ } )
542
+ ]
543
+ } )
544
+ } )
545
+ ]
546
+ } )
547
+ ]
548
+ } )
549
+ ) ;
550
+ } ) ;
312
551
} ) ;
313
552
} ) ;
0 commit comments