11import { describe , it , expect , test } from 'vitest'
22import { SelectorParser , parse_selector } from './parse-selector'
3- import { CSSDataArena } from './arena'
3+ import { ATTR_OPERATOR_EQUAL , CSSDataArena } from './arena'
44import {
55 NODE_SELECTOR ,
66 NODE_SELECTOR_LIST ,
@@ -16,6 +16,9 @@ import {
1616 NODE_SELECTOR_NTH ,
1717 NODE_SELECTOR_NTH_OF ,
1818 NODE_SELECTOR_LANG ,
19+ ATTR_FLAG_NONE ,
20+ ATTR_FLAG_CASE_INSENSITIVE ,
21+ ATTR_FLAG_CASE_SENSITIVE ,
1922} from './arena'
2023
2124// Tests using the exported parse_selector() function
@@ -520,6 +523,114 @@ describe('SelectorParser', () => {
520523 // Content now stores just the attribute name
521524 expect ( getNodeContent ( arena , source , child ) ) . toBe ( 'data-test' )
522525 } )
526+
527+ it ( 'should parse attribute with case-insensitive flag' , ( ) => {
528+ const { arena, rootNode, source } = parseSelectorInternal ( '[type="text" i]' )
529+
530+ expect ( rootNode ) . not . toBeNull ( )
531+ if ( ! rootNode ) return
532+
533+ const selectorWrapper = arena . get_first_child ( rootNode )
534+ const child = arena . get_first_child ( selectorWrapper )
535+ expect ( arena . get_type ( child ) ) . toBe ( NODE_SELECTOR_ATTRIBUTE )
536+ expect ( getNodeText ( arena , source , child ) ) . toBe ( '[type="text" i]' )
537+ expect ( getNodeContent ( arena , source , child ) ) . toBe ( 'type' )
538+ expect ( arena . get_attr_flags ( child ) ) . toBe ( ATTR_FLAG_CASE_INSENSITIVE )
539+ } )
540+
541+ it ( 'should parse attribute with case-insensitive flag' , ( ) => {
542+ const root = parse_selector ( '[type="text" i]' )
543+
544+ expect ( root ) . not . toBeNull ( )
545+ if ( ! root ) return
546+
547+ expect ( root . type ) . toBe ( NODE_SELECTOR_LIST )
548+ let selector = root . first_child !
549+ expect ( selector . type ) . toBe ( NODE_SELECTOR )
550+ let attr = selector . first_child !
551+ expect ( attr . type ) . toBe ( NODE_SELECTOR_ATTRIBUTE )
552+ expect ( attr . attr_flags ) . toBe ( ATTR_FLAG_CASE_INSENSITIVE )
553+ expect ( attr . attr_operator ) . toBe ( ATTR_OPERATOR_EQUAL )
554+ } )
555+
556+ it ( 'should parse attribute with case-sensitive flag' , ( ) => {
557+ const { arena, rootNode, source } = parseSelectorInternal ( '[type="text" s]' )
558+
559+ expect ( rootNode ) . not . toBeNull ( )
560+ if ( ! rootNode ) return
561+
562+ const selectorWrapper = arena . get_first_child ( rootNode )
563+ const child = arena . get_first_child ( selectorWrapper )
564+ expect ( arena . get_type ( child ) ) . toBe ( NODE_SELECTOR_ATTRIBUTE )
565+ expect ( getNodeText ( arena , source , child ) ) . toBe ( '[type="text" s]' )
566+ expect ( getNodeContent ( arena , source , child ) ) . toBe ( 'type' )
567+ expect ( arena . get_attr_flags ( child ) ) . toBe ( ATTR_FLAG_CASE_SENSITIVE )
568+ } )
569+
570+ it ( 'should parse attribute with uppercase case-insensitive flag' , ( ) => {
571+ const { arena, rootNode, source } = parseSelectorInternal ( '[type="text" I]' )
572+
573+ expect ( rootNode ) . not . toBeNull ( )
574+ if ( ! rootNode ) return
575+
576+ const selectorWrapper = arena . get_first_child ( rootNode )
577+ const child = arena . get_first_child ( selectorWrapper )
578+ expect ( arena . get_type ( child ) ) . toBe ( NODE_SELECTOR_ATTRIBUTE )
579+ expect ( arena . get_attr_flags ( child ) ) . toBe ( ATTR_FLAG_CASE_INSENSITIVE )
580+ } )
581+
582+ it ( 'should parse attribute with whitespace before flag' , ( ) => {
583+ const { arena, rootNode, source } = parseSelectorInternal ( '[type="text" i]' )
584+
585+ expect ( rootNode ) . not . toBeNull ( )
586+ if ( ! rootNode ) return
587+
588+ const selectorWrapper = arena . get_first_child ( rootNode )
589+ const child = arena . get_first_child ( selectorWrapper )
590+ expect ( arena . get_type ( child ) ) . toBe ( NODE_SELECTOR_ATTRIBUTE )
591+ expect ( arena . get_attr_flags ( child ) ) . toBe ( ATTR_FLAG_CASE_INSENSITIVE )
592+ } )
593+
594+ it ( 'should parse attribute without flag' , ( ) => {
595+ const { arena, rootNode, source } = parseSelectorInternal ( '[type="text"]' )
596+
597+ expect ( rootNode ) . not . toBeNull ( )
598+ if ( ! rootNode ) return
599+
600+ const selectorWrapper = arena . get_first_child ( rootNode )
601+ const child = arena . get_first_child ( selectorWrapper )
602+ expect ( arena . get_type ( child ) ) . toBe ( NODE_SELECTOR_ATTRIBUTE )
603+ expect ( arena . get_attr_flags ( child ) ) . toBe ( ATTR_FLAG_NONE )
604+ } )
605+
606+ it ( 'should handle flag with various operators' , ( ) => {
607+ // Test with ^= operator
608+ const test1 = parseSelectorInternal ( '[class^="btn" i]' )
609+ if ( ! test1 . rootNode ) throw new Error ( 'Expected rootNode' )
610+ const wrapper1 = test1 . arena . get_first_child ( test1 . rootNode )
611+ if ( ! wrapper1 ) throw new Error ( 'Expected wrapper1' )
612+ const child1 = test1 . arena . get_first_child ( wrapper1 )
613+ if ( ! child1 ) throw new Error ( 'Expected child1' )
614+ expect ( test1 . arena . get_attr_flags ( child1 ) ) . toBe ( ATTR_FLAG_CASE_INSENSITIVE )
615+
616+ // Test with $= operator
617+ const test2 = parseSelectorInternal ( '[class$="btn" s]' )
618+ if ( ! test2 . rootNode ) throw new Error ( 'Expected rootNode' )
619+ const wrapper2 = test2 . arena . get_first_child ( test2 . rootNode )
620+ if ( ! wrapper2 ) throw new Error ( 'Expected wrapper2' )
621+ const child2 = test2 . arena . get_first_child ( wrapper2 )
622+ if ( ! child2 ) throw new Error ( 'Expected child2' )
623+ expect ( test2 . arena . get_attr_flags ( child2 ) ) . toBe ( ATTR_FLAG_CASE_SENSITIVE )
624+
625+ // Test with ~= operator
626+ const test3 = parseSelectorInternal ( '[class~="active" i]' )
627+ if ( ! test3 . rootNode ) throw new Error ( 'Expected rootNode' )
628+ const wrapper3 = test3 . arena . get_first_child ( test3 . rootNode )
629+ if ( ! wrapper3 ) throw new Error ( 'Expected wrapper3' )
630+ const child3 = test3 . arena . get_first_child ( wrapper3 )
631+ if ( ! child3 ) throw new Error ( 'Expected child3' )
632+ expect ( test3 . arena . get_attr_flags ( child3 ) ) . toBe ( ATTR_FLAG_CASE_INSENSITIVE )
633+ } )
523634 } )
524635
525636 describe ( 'Combinators' , ( ) => {
0 commit comments