@@ -893,4 +893,142 @@ describe('RenderHTML', () => {
893893 expect ( queryByText ( '\n' , { normalizer : ( s ) => s } ) ) . toBeNull ( ) ;
894894 } ) ;
895895 } ) ;
896+ describe ( 'regarding key generation in renderChildren' , ( ) => {
897+ it ( 'should generate unique keys for sibling elements with the same tag name' , ( ) => {
898+ const capturedKeys : string [ ] = [ ] ;
899+ const renderChild = jest . fn ( ( { key } ) => {
900+ capturedKeys . push ( key ) ;
901+ return null ;
902+ } ) ;
903+ const DivRenderer : CustomTextualRenderer = jest . fn ( function DivRenderer ( {
904+ TDefaultRenderer,
905+ ...props
906+ } ) {
907+ return (
908+ < TDefaultRenderer { ...props } >
909+ < TNodeChildrenRenderer
910+ renderChild = { renderChild }
911+ tnode = { props . tnode }
912+ />
913+ </ TDefaultRenderer >
914+ ) ;
915+ } ) ;
916+ render (
917+ < RenderHTML
918+ source = { {
919+ html : '<div><p>One</p><p>Two</p></div>'
920+ } }
921+ debug = { false }
922+ renderers = { { div : DivRenderer } }
923+ contentWidth = { 100 }
924+ />
925+ ) ;
926+ expect ( capturedKeys . length ) . toBeGreaterThanOrEqual ( 2 ) ;
927+ expect ( new Set ( capturedKeys ) . size ) . toBe ( capturedKeys . length ) ;
928+ } ) ;
929+ it ( 'should generate unique keys for elements with the same tag and same nodeIndex in different subtrees' , ( ) => {
930+ const capturedKeys : string [ ] = [ ] ;
931+ const renderChild = jest . fn ( ( { key } ) => {
932+ capturedKeys . push ( key ) ;
933+ return null ;
934+ } ) ;
935+ const DivRenderer : CustomTextualRenderer = jest . fn ( function DivRenderer ( {
936+ TDefaultRenderer,
937+ ...props
938+ } ) {
939+ return (
940+ < TDefaultRenderer { ...props } >
941+ < TNodeChildrenRenderer
942+ renderChild = { renderChild }
943+ tnode = { props . tnode }
944+ />
945+ </ TDefaultRenderer >
946+ ) ;
947+ } ) ;
948+ render (
949+ < RenderHTML
950+ source = { {
951+ html : '<div><div><p>Nested One</p></div><div><p>Nested Two</p></div></div>'
952+ } }
953+ debug = { false }
954+ renderers = { { div : DivRenderer } }
955+ contentWidth = { 100 }
956+ />
957+ ) ;
958+ expect ( new Set ( capturedKeys ) . size ) . toBe ( capturedKeys . length ) ;
959+ } ) ;
960+ it ( 'should generate a key matching the exact expected string including parent path' , ( ) => {
961+ const capturedKeys : string [ ] = [ ] ;
962+ const renderChild = jest . fn ( ( { key } ) => {
963+ capturedKeys . push ( key ) ;
964+ return null ;
965+ } ) ;
966+ const DivRenderer : CustomTextualRenderer = jest . fn ( function DivRenderer ( {
967+ TDefaultRenderer,
968+ ...props
969+ } ) {
970+ return (
971+ < TDefaultRenderer { ...props } >
972+ < TNodeChildrenRenderer
973+ renderChild = { renderChild }
974+ tnode = { props . tnode }
975+ />
976+ </ TDefaultRenderer >
977+ ) ;
978+ } ) ;
979+ render (
980+ < RenderHTML
981+ source = { {
982+ html : '<div><p>One</p><p>Two</p></div>'
983+ } }
984+ debug = { false }
985+ renderers = { { div : DivRenderer } }
986+ contentWidth = { 100 }
987+ />
988+ ) ;
989+ // The key encodes the full ancestor path: <p> at index 0 inside <div> at index 0
990+ // inside synthetic <body> at index 0 inside TDocument (tagName "html") at index 0
991+ expect ( capturedKeys [ 0 ] ) . toBe (
992+ 'tnode_childTnode--p-0-div-0-body-0-html-0'
993+ ) ;
994+ // Second <p> differs only in its own nodeIndex (1 instead of 0)
995+ expect ( capturedKeys [ 1 ] ) . toBe (
996+ 'tnode_childTnode--p-1-div-0-body-0-html-0'
997+ ) ;
998+ } ) ;
999+ it ( 'should generate keys with the tnode_childTnode- prefix' , ( ) => {
1000+ const capturedKeys : string [ ] = [ ] ;
1001+ const renderChild = jest . fn ( ( { key } ) => {
1002+ capturedKeys . push ( key ) ;
1003+ return null ;
1004+ } ) ;
1005+ const DivRenderer : CustomTextualRenderer = jest . fn ( function DivRenderer ( {
1006+ TDefaultRenderer,
1007+ ...props
1008+ } ) {
1009+ return (
1010+ < TDefaultRenderer { ...props } >
1011+ < TNodeChildrenRenderer
1012+ renderChild = { renderChild }
1013+ tnode = { props . tnode }
1014+ />
1015+ </ TDefaultRenderer >
1016+ ) ;
1017+ } ) ;
1018+ render (
1019+ < RenderHTML
1020+ source = { {
1021+ html : '<div><p>One</p><p>Two</p></div>'
1022+ } }
1023+ debug = { false }
1024+ renderers = { { div : DivRenderer } }
1025+ contentWidth = { 100 }
1026+ />
1027+ ) ;
1028+ expect ( capturedKeys . length ) . toBeGreaterThan ( 0 ) ;
1029+ for ( const key of capturedKeys ) {
1030+ expect ( key ) . toMatch ( / ^ t n o d e _ c h i l d T n o d e - / ) ;
1031+ }
1032+ } ) ;
1033+ } ) ;
8961034} ) ;
0 commit comments