@@ -485,3 +485,117 @@ describe('TagDropdown Tag Ordering', () => {
485485 expect ( tagIndexMap . get ( 'nonexistent' ) ) . toBeUndefined ( )
486486 } )
487487} )
488+
489+ describe ( 'TagDropdown Tag Selection Logic' , ( ) => {
490+ test ( 'should handle existing closing bracket correctly when editing tags' , ( ) => {
491+ const testCases = [
492+ {
493+ description : 'should remove existing closing bracket from incomplete tag' ,
494+ inputValue : 'Hello <start.response.>' ,
495+ cursorPosition : 21 , // cursor after the dot
496+ tag : 'start.response.input' ,
497+ expectedResult : 'Hello <start.response.input>' ,
498+ } ,
499+ {
500+ description : 'should remove existing closing bracket when replacing tag content' ,
501+ inputValue : 'Hello <start.response.input>' ,
502+ cursorPosition : 22 , // cursor after 'response.'
503+ tag : 'start.response.data' ,
504+ expectedResult : 'Hello <start.response.data>' ,
505+ } ,
506+ {
507+ description : 'should preserve content after closing bracket' ,
508+ inputValue : 'Hello <start.response.> world' ,
509+ cursorPosition : 21 ,
510+ tag : 'start.response.input' ,
511+ expectedResult : 'Hello <start.response.input> world' ,
512+ } ,
513+ {
514+ description :
515+ 'should not affect closing bracket if text between contains invalid characters' ,
516+ inputValue : 'Hello <start.response.input> and <other>' ,
517+ cursorPosition : 22 ,
518+ tag : 'start.response.data' ,
519+ expectedResult : 'Hello <start.response.data> and <other>' ,
520+ } ,
521+ {
522+ description : 'should handle case with no existing closing bracket' ,
523+ inputValue : 'Hello <start.response' ,
524+ cursorPosition : 21 ,
525+ tag : 'start.response.input' ,
526+ expectedResult : 'Hello <start.response.input>' ,
527+ } ,
528+ ]
529+
530+ testCases . forEach ( ( { description, inputValue, cursorPosition, tag, expectedResult } ) => {
531+ // Simulate the handleTagSelect logic
532+ const textBeforeCursor = inputValue . slice ( 0 , cursorPosition )
533+ const textAfterCursor = inputValue . slice ( cursorPosition )
534+ const lastOpenBracket = textBeforeCursor . lastIndexOf ( '<' )
535+
536+ // Apply the new logic for handling existing closing brackets
537+ const nextCloseBracket = textAfterCursor . indexOf ( '>' )
538+ let remainingTextAfterCursor = textAfterCursor
539+
540+ if ( nextCloseBracket !== - 1 ) {
541+ const textBetween = textAfterCursor . slice ( 0 , nextCloseBracket )
542+ if ( / ^ [ a - z A - Z 0 - 9 . _ ] * $ / . test ( textBetween ) ) {
543+ remainingTextAfterCursor = textAfterCursor . slice ( nextCloseBracket + 1 )
544+ }
545+ }
546+
547+ const newValue = `${ textBeforeCursor . slice ( 0 , lastOpenBracket ) } <${ tag } >${ remainingTextAfterCursor } `
548+
549+ expect ( newValue ) . toBe ( expectedResult )
550+ } )
551+ } )
552+
553+ test ( 'should validate tag-like character regex correctly' , ( ) => {
554+ const regex = / ^ [ a - z A - Z 0 - 9 . _ ] * $ /
555+
556+ // Valid tag-like text
557+ expect ( regex . test ( '' ) ) . toBe ( true ) // empty string
558+ expect ( regex . test ( 'input' ) ) . toBe ( true )
559+ expect ( regex . test ( 'response.data' ) ) . toBe ( true )
560+ expect ( regex . test ( 'user_name' ) ) . toBe ( true )
561+ expect ( regex . test ( 'item123' ) ) . toBe ( true )
562+ expect ( regex . test ( 'response.data.item_1' ) ) . toBe ( true )
563+
564+ // Invalid tag-like text (should not remove closing bracket)
565+ expect ( regex . test ( 'input> and more' ) ) . toBe ( false )
566+ expect ( regex . test ( 'response data' ) ) . toBe ( false ) // space
567+ expect ( regex . test ( 'user-name' ) ) . toBe ( false ) // hyphen
568+ expect ( regex . test ( 'data[' ) ) . toBe ( false ) // bracket
569+ expect ( regex . test ( 'response.data!' ) ) . toBe ( false ) // exclamation
570+ } )
571+
572+ test ( 'should find correct position of last open bracket' , ( ) => {
573+ const testCases = [
574+ { input : 'Hello <start.response' , expected : 6 } ,
575+ { input : 'Hello <var> and <start.response' , expected : 16 } ,
576+ { input : 'No brackets here' , expected : - 1 } ,
577+ { input : '<start.response' , expected : 0 } ,
578+ { input : 'Multiple < < < <last' , expected : 15 } ,
579+ ]
580+
581+ testCases . forEach ( ( { input, expected } ) => {
582+ const lastOpenBracket = input . lastIndexOf ( '<' )
583+ expect ( lastOpenBracket ) . toBe ( expected )
584+ } )
585+ } )
586+
587+ test ( 'should find correct position of next closing bracket' , ( ) => {
588+ const testCases = [
589+ { input : 'input>' , expected : 5 } ,
590+ { input : 'response.data> more text' , expected : 13 } ,
591+ { input : 'no closing bracket' , expected : - 1 } ,
592+ { input : '>' , expected : 0 } ,
593+ { input : 'multiple > > > >last' , expected : 9 } ,
594+ ]
595+
596+ testCases . forEach ( ( { input, expected } ) => {
597+ const nextCloseBracket = input . indexOf ( '>' )
598+ expect ( nextCloseBracket ) . toBe ( expected )
599+ } )
600+ } )
601+ } )
0 commit comments