@@ -306,4 +306,280 @@ describe('processLabel', () => {
306306 expect ( processLabel ( target , '.redirect-label-class-four' ) ) . toEqual ( 'content inside header' ) ;
307307 expect ( processLabel ( target , '.redirect-label-class-five' ) ) . toEqual ( '' ) ;
308308 } ) ;
309+
310+ describe ( 'with selectionMode parameter' , ( ) => {
311+ test ( 'returns single label when selectionMode is "single" (default)' , ( ) => {
312+ const { container } = render (
313+ < div >
314+ < div id = "target" >
315+ < div className = "item" > Item 1</ div >
316+ < div className = "item" > Item 2</ div >
317+ < div className = "item" > Item 3</ div >
318+ </ div >
319+ </ div >
320+ ) ;
321+ const target = container . querySelector ( '#target' ) as HTMLElement ;
322+
323+ expect ( processLabel ( target , '.item' , 'single' ) ) . toEqual ( 'Item 1' ) ;
324+ expect ( processLabel ( target , '.item' ) ) . toEqual ( 'Item 1' ) ; // default is 'single'
325+ } ) ;
326+
327+ test ( 'returns array of labels when selectionMode is "multi"' , ( ) => {
328+ const { container } = render (
329+ < div >
330+ < div id = "target" >
331+ < div className = "item" > Item 1</ div >
332+ < div className = "item" > Item 2</ div >
333+ < div className = "item" > Item 3</ div >
334+ </ div >
335+ </ div >
336+ ) ;
337+ const target = container . querySelector ( '#target' ) as HTMLElement ;
338+
339+ expect ( processLabel ( target , '.item' , 'multi' ) ) . toEqual ( [ 'Item 1' , 'Item 2' , 'Item 3' ] ) ;
340+ } ) ;
341+
342+ test ( 'returns empty array when no elements match in multi mode' , ( ) => {
343+ const { container } = render (
344+ < div >
345+ < div id = "target" >
346+ < div className = "item" > Item 1</ div >
347+ </ div >
348+ </ div >
349+ ) ;
350+ const target = container . querySelector ( '#target' ) as HTMLElement ;
351+
352+ expect ( processLabel ( target , '.nonexistent' , 'multi' ) ) . toEqual ( [ ] ) ;
353+ } ) ;
354+
355+ test ( 'filters out empty labels in multi mode' , ( ) => {
356+ const { container } = render (
357+ < div >
358+ < div id = "target" >
359+ < div className = "item" > Item 1</ div >
360+ < div className = "item" > </ div >
361+ < div className = "item" > Item 3</ div >
362+ </ div >
363+ </ div >
364+ ) ;
365+ const target = container . querySelector ( '#target' ) as HTMLElement ;
366+
367+ expect ( processLabel ( target , '.item' , 'multi' ) ) . toEqual ( [ 'Item 1' , 'Item 3' ] ) ;
368+ } ) ;
369+
370+ test ( 'handles nested label resolution in multi mode' , ( ) => {
371+ const { container } = render (
372+ < div >
373+ < div id = "target" >
374+ < div className = "item" { ...getAnalyticsLabelAttribute ( '.nested' ) } >
375+ < span className = "nested" > Nested 1</ span >
376+ </ div >
377+ < div className = "item" { ...getAnalyticsLabelAttribute ( '.nested' ) } >
378+ < span className = "nested" > Nested 2</ span >
379+ </ div >
380+ < div className = "item" > Direct 3</ div >
381+ </ div >
382+ </ div >
383+ ) ;
384+ const target = container . querySelector ( '#target' ) as HTMLElement ;
385+
386+ expect ( processLabel ( target , '.item' , 'multi' ) ) . toEqual ( [ 'Nested 1' , 'Nested 2' , 'Direct 3' ] ) ;
387+ } ) ;
388+
389+ test ( 'flattens nested arrays from recursive processing in multi mode' , ( ) => {
390+ const { container } = render (
391+ < div >
392+ < div id = "target" >
393+ < div className = "item" { ...getAnalyticsLabelAttribute ( '.nested' ) } >
394+ < span className = "nested" > Nested 1</ span >
395+ < span className = "nested" > Nested 2</ span >
396+ </ div >
397+ < div className = "item" > Direct</ div >
398+ </ div >
399+ </ div >
400+ ) ;
401+ const target = container . querySelector ( '#target' ) as HTMLElement ;
402+
403+ const result = processLabel ( target , '.item' , 'multi' ) ;
404+ expect ( Array . isArray ( result ) ) . toBe ( true ) ;
405+ expect ( ( result as string [ ] ) . every ( item => typeof item === 'string' ) ) . toBe ( true ) ;
406+ } ) ;
407+
408+ test ( 'handles aria-label in multi mode' , ( ) => {
409+ const { container } = render (
410+ < div >
411+ < div id = "target" >
412+ < div className = "item" aria-label = "Label 1" >
413+ Content 1
414+ </ div >
415+ < div className = "item" aria-label = "Label 2" >
416+ Content 2
417+ </ div >
418+ < div className = "item" > Content 3</ div >
419+ </ div >
420+ </ div >
421+ ) ;
422+ const target = container . querySelector ( '#target' ) as HTMLElement ;
423+
424+ expect ( processLabel ( target , '.item' , 'multi' ) ) . toEqual ( [ 'Label 1' , 'Label 2' , 'Content 3' ] ) ;
425+ } ) ;
426+
427+ test ( 'works with LabelIdentifier object in multi mode' , ( ) => {
428+ const { container } = render (
429+ < div >
430+ < div id = "target" >
431+ < div className = "item" > Item 1</ div >
432+ < div className = "item" > Item 2</ div >
433+ </ div >
434+ </ div >
435+ ) ;
436+ const target = container . querySelector ( '#target' ) as HTMLElement ;
437+
438+ expect ( processLabel ( target , { selector : '.item' } , 'multi' ) ) . toEqual ( [ 'Item 1' , 'Item 2' ] ) ;
439+ } ) ;
440+
441+ test ( 'returns empty array when selector is undefined in multi mode' , ( ) => {
442+ const { container } = render (
443+ < div >
444+ < div id = "target" >
445+ < div className = "item" > Item 1</ div >
446+ </ div >
447+ </ div >
448+ ) ;
449+ const target = container . querySelector ( '#target' ) as HTMLElement ;
450+
451+ expect ( processLabel ( target , { selector : undefined } , 'multi' ) ) . toEqual ( [ ] ) ;
452+ } ) ;
453+
454+ test ( 'returns empty array when labelIdentifier is null in multi mode' , ( ) => {
455+ const { container } = render (
456+ < div >
457+ < div id = "target" >
458+ < div className = "item" > Item 1</ div >
459+ </ div >
460+ </ div >
461+ ) ;
462+ const target = container . querySelector ( '#target' ) as HTMLElement ;
463+
464+ expect ( processLabel ( target , null , 'multi' ) ) . toEqual ( [ ] ) ;
465+ } ) ;
466+
467+ test ( 'returns empty array when node is null in multi mode' , ( ) => {
468+ expect ( processLabel ( null , '.item' , 'multi' ) ) . toEqual ( [ ] ) ;
469+ } ) ;
470+
471+ test ( 'returns first non-empty labels when selector is an array in multi mode' , ( ) => {
472+ const { container } = render (
473+ < div >
474+ < div id = "target" >
475+ < div className = "wrong-class" > Wrong 1</ div >
476+ < div className = "item" > Item 1</ div >
477+ < div className = "item" > Item 2</ div >
478+ < div className = "other" > Other 1</ div >
479+ </ div >
480+ </ div >
481+ ) ;
482+ const target = container . querySelector ( '#target' ) as HTMLElement ;
483+
484+ // Should return first successful selector's results
485+ expect ( processLabel ( target , { selector : [ '.nonexistent' , '.item' , '.other' ] } , 'multi' ) ) . toEqual ( [
486+ 'Item 1' ,
487+ 'Item 2' ,
488+ ] ) ;
489+ } ) ;
490+
491+ test ( 'returns empty array when all selectors in array fail in multi mode' , ( ) => {
492+ const { container } = render (
493+ < div >
494+ < div id = "target" >
495+ < div className = "item" > Item 1</ div >
496+ </ div >
497+ </ div >
498+ ) ;
499+ const target = container . querySelector ( '#target' ) as HTMLElement ;
500+
501+ expect ( processLabel ( target , { selector : [ '.nonexistent1' , '.nonexistent2' , '.nonexistent3' ] } , 'multi' ) ) . toEqual (
502+ [ ]
503+ ) ;
504+ } ) ;
505+
506+ test ( 'respects rootSelector property in multi mode' , ( ) => {
507+ const { container } = render (
508+ < div className = "root-class" >
509+ < div className = "item" > Root Item 1</ div >
510+ < div className = "item" > Root Item 2</ div >
511+ < div id = "target" >
512+ < div className = "item" > Inner Item 1</ div >
513+ < div className = "item" > Inner Item 2</ div >
514+ </ div >
515+ </ div >
516+ ) ;
517+ const target = container . querySelector ( '#target' ) as HTMLElement ;
518+
519+ expect ( processLabel ( target , { selector : '.item' , rootSelector : '.root-class' } , 'multi' ) ) . toEqual ( [
520+ 'Root Item 1' ,
521+ 'Root Item 2' ,
522+ 'Inner Item 1' ,
523+ 'Inner Item 2' ,
524+ ] ) ;
525+ } ) ;
526+
527+ test ( 'respects root="component" property in multi mode' , ( ) => {
528+ const { container } = render (
529+ < >
530+ < div { ...getAnalyticsMetadataAttribute ( { component : { name : 'ComponentName' } } ) } >
531+ < div className = "item" > Component Item 1</ div >
532+ < div className = "item" > Component Item 2</ div >
533+ < div id = "target" >
534+ < div className = "item" > Inner Item 1</ div >
535+ < div className = "item" > Inner Item 2</ div >
536+ </ div >
537+ </ div >
538+ </ >
539+ ) ;
540+ const target = container . querySelector ( '#target' ) as HTMLElement ;
541+
542+ // querySelectorAll finds ALL descendants from the component root
543+ expect ( processLabel ( target , { selector : '.item' , root : 'component' } , 'multi' ) ) . toEqual ( [
544+ 'Component Item 1' ,
545+ 'Component Item 2' ,
546+ 'Inner Item 1' ,
547+ 'Inner Item 2' ,
548+ ] ) ;
549+ } ) ;
550+
551+ test ( 'respects root="body" property in multi mode' , ( ) => {
552+ const { container } = render (
553+ < >
554+ < div className = "outer-item" > Outer Item 1</ div >
555+ < div className = "outer-item" > Outer Item 2</ div >
556+ < div id = "target" >
557+ < div className = "outer-item" > Inner Item 1</ div >
558+ </ div >
559+ </ >
560+ ) ;
561+ const target = container . querySelector ( '#target' ) as HTMLElement ;
562+
563+ expect ( processLabel ( target , { selector : '.outer-item' , root : 'body' } , 'multi' ) ) . toEqual ( [
564+ 'Outer Item 1' ,
565+ 'Outer Item 2' ,
566+ 'Inner Item 1' ,
567+ ] ) ;
568+ } ) ;
569+ } ) ;
570+
571+ describe ( 'edge cases with array selectors in single mode' , ( ) => {
572+ test ( 'returns empty string when all selectors in array fail' , ( ) => {
573+ const { container } = render (
574+ < div >
575+ < div id = "target" >
576+ < div className = "item" > Item 1</ div >
577+ </ div >
578+ </ div >
579+ ) ;
580+ const target = container . querySelector ( '#target' ) as HTMLElement ;
581+
582+ expect ( processLabel ( target , { selector : [ '.nonexistent1' , '.nonexistent2' ] } ) ) . toEqual ( '' ) ;
583+ } ) ;
584+ } ) ;
309585} ) ;
0 commit comments