@@ -492,14 +492,27 @@ class TestCase {
492492
493493// Validators
494494const queueSizeStore = { } ;
495+ const extractedValues = { } ;
495496
496497function extractQueueSize ( responses ) {
497498 const allText = responses . map ( r => r . text ) . join ( ' ' ) ;
499+ // Match "X tracks" pattern first (more specific)
500+ const tracksMatch = allText . match ( / ( \d + ) \s * t r a c k / i) ;
501+ if ( tracksMatch ) return parseInt ( tracksMatch [ 1 ] , 10 ) ;
502+ // Fall back to first number
498503 const match = allText . match ( / \b ( \d + ) \b / ) ;
499504 if ( ! match ) return null ;
500505 return parseInt ( match [ 1 ] , 10 ) ;
501506}
502507
508+ function extractTrackCountFromResponse ( responses ) {
509+ const allText = responses . map ( r => r . text ) . join ( ' ' ) ;
510+ // Match patterns like "(150 tracks)" or "150 tracks"
511+ const match = allText . match ( / \( ( \d + ) \s * t r a c k s ? \) / i) || allText . match ( / ( \d + ) \s * t r a c k s ? / i) ;
512+ if ( ! match ) return null ;
513+ return parseInt ( match [ 1 ] , 10 ) ;
514+ }
515+
503516const validators = {
504517 containsText : ( text ) => ( responses ) => {
505518 const allText = responses . map ( r => r . text ) . join ( ' ' ) ;
@@ -568,6 +581,72 @@ const validators = {
568581 }
569582 if ( size >= baseline + minIncrease ) return true ;
570583 return `Expected queue size to increase by ${ minIncrease } from ${ baseline } , got ${ size } ` ;
584+ } ,
585+
586+ // Verify queue size increased by EXACTLY N (not double, not less)
587+ queueSizeIncreaseExactly : ( key , exactIncrease ) => ( responses ) => {
588+ const size = extractQueueSize ( responses ) ;
589+ if ( size === null ) return 'Could not parse queue size from response' ;
590+ const baseline = queueSizeStore [ key ] ;
591+ if ( baseline === undefined || baseline === null ) {
592+ return `No baseline queue size recorded for "${ key } "` ;
593+ }
594+ const actualIncrease = size - baseline ;
595+
596+ // Exact match - no output
597+ if ( actualIncrease === exactIncrease ) return true ;
598+
599+ // Disable tolerance for very small expected increases (1-2 tracks),
600+ // where a "90%" tolerance would allow clearly incorrect results (e.g., 0 of 1).
601+ if ( exactIncrease >= 3 ) {
602+ const tolerance = Math . floor ( exactIncrease * 0.9 ) ;
603+ if ( actualIncrease >= tolerance && actualIncrease < exactIncrease ) {
604+ console . log ( ` ⚠️ WARNING: Queue increased by ${ actualIncrease } (expected ${ exactIncrease } , baseline: ${ baseline } → ${ size } )` ) ;
605+ return true ;
606+ }
607+ }
608+
609+ // Outside tolerance or small exact value - fail
610+ return `❌ FAIL: Queue increased by ${ actualIncrease } (expected exactly ${ exactIncrease } , baseline: ${ baseline } → ${ size } )` ;
611+ } ,
612+
613+ // Extract and store track count from search results (e.g., "(50 tracks)")
614+ extractAndStoreTrackCount : ( key ) => ( responses ) => {
615+ const count = extractTrackCountFromResponse ( responses ) ;
616+ if ( count === null ) return 'Could not extract track count from response' ;
617+ extractedValues [ key ] = count ;
618+ return true ;
619+ } ,
620+
621+ // Verify queue increased by stored track count (with tolerance for duplicates/blacklist)
622+ queueSizeIncreasedByStoredCount : ( baselineKey , countKey , tolerancePercent = 10 ) => ( responses ) => {
623+ const size = extractQueueSize ( responses ) ;
624+ if ( size === null ) return 'Could not parse queue size from response' ;
625+ const baseline = queueSizeStore [ baselineKey ] ;
626+ const expectedCount = extractedValues [ countKey ] ;
627+ if ( baseline === undefined ) return `No baseline recorded for "${ baselineKey } "` ;
628+ if ( expectedCount === undefined ) return `No track count recorded for "${ countKey } "` ;
629+
630+ const actualIncrease = size - baseline ;
631+ const minExpected = Math . floor ( expectedCount * ( 1 - tolerancePercent / 100 ) ) ;
632+ const maxExpected = expectedCount ; // Should not exceed expected (no doubling!)
633+
634+ // Exact match - no output
635+ if ( actualIncrease === expectedCount ) return true ;
636+
637+ // Within tolerance but not exact - warning but pass
638+ if ( actualIncrease >= minExpected && actualIncrease < expectedCount ) {
639+ console . log ( ` ⚠️ WARNING: Queue increased by ${ actualIncrease } (expected ${ expectedCount } , baseline: ${ baseline } → ${ size } , tolerance: ${ minExpected } -${ maxExpected } )` ) ;
640+ return true ;
641+ }
642+
643+ // Exceeded expected (possible doubling bug) - fail
644+ if ( actualIncrease > maxExpected ) {
645+ return `❌ FAIL: Queue increased by ${ actualIncrease } but expected max ${ maxExpected } - possible DUPLICATE QUEUEING BUG! (baseline: ${ baseline } → ${ size } )` ;
646+ }
647+
648+ // Below minimum (too many filtered) - fail
649+ return `❌ FAIL: Queue increased by ${ actualIncrease } , expected ${ minExpected } -${ maxExpected } (based on ${ expectedCount } tracks, baseline: ${ baseline } → ${ size } )` ;
571650 }
572651} ;
573652
@@ -730,6 +809,17 @@ const testSuiteArray = [
730809 // PHASE 4: BUILD UP THE QUEUE (add tracks for later tests)
731810 // ═══════════════════════════════════════════════════════════════════
732811
812+ // Get baseline queue size before adding tracks
813+ new TestCase (
814+ 'Queue Size - Initial Baseline' ,
815+ 'size' ,
816+ validators . and (
817+ validators . responseCount ( 1 , 2 ) ,
818+ validators . recordQueueSize ( 'initialBaseline' )
819+ ) ,
820+ 4
821+ ) ,
822+
733823 new TestCase (
734824 'Add Track #1 - Foo Fighters' ,
735825 'add Foo Fighters - Best Of You' ,
@@ -744,6 +834,18 @@ const testSuiteArray = [
744834 7
745835 ) ,
746836
837+ // Verify exactly 1 track was added
838+ new TestCase (
839+ 'Queue Size - After Track #1 (+1)' ,
840+ 'size' ,
841+ validators . and (
842+ validators . responseCount ( 1 , 2 ) ,
843+ validators . queueSizeIncreaseExactly ( 'initialBaseline' , 1 ) ,
844+ validators . recordQueueSize ( 'afterTrack1' )
845+ ) ,
846+ 4
847+ ) ,
848+
747849 new TestCase (
748850 'Add Track - Duplicate Detection' ,
749851 'add Foo Fighters - Best Of You' ,
@@ -768,6 +870,18 @@ const testSuiteArray = [
768870 7
769871 ) ,
770872
873+ // Verify exactly 1 more track added (total +2 from initial)
874+ new TestCase (
875+ 'Queue Size - After Track #2 (+1)' ,
876+ 'size' ,
877+ validators . and (
878+ validators . responseCount ( 1 , 2 ) ,
879+ validators . queueSizeIncreaseExactly ( 'afterTrack1' , 1 ) ,
880+ validators . recordQueueSize ( 'afterTrack2' )
881+ ) ,
882+ 4
883+ ) ,
884+
771885 new TestCase (
772886 'Add Track #3 - Queen' ,
773887 'add Queen - Bohemian Rhapsody' ,
@@ -796,6 +910,21 @@ const testSuiteArray = [
796910 7
797911 ) ,
798912
913+ // Search album first to get track count
914+ new TestCase (
915+ 'Search Album - Abbey Road (get track count)' ,
916+ 'searchalbum abbey road' ,
917+ validators . and (
918+ validators . responseCount ( 1 , 2 ) ,
919+ validators . or (
920+ validators . containsText ( 'Beatles' ) ,
921+ validators . containsText ( 'Abbey Road' )
922+ ) ,
923+ validators . extractAndStoreTrackCount ( 'abbeyRoadTracks' )
924+ ) ,
925+ 5
926+ ) ,
927+
799928 new TestCase (
800929 'Queue Size - Baseline Before Album' ,
801930 'size' ,
@@ -820,17 +949,30 @@ const testSuiteArray = [
820949 10
821950 ) ,
822951
952+ // Verify album tracks were added (not doubled!)
823953 new TestCase (
824- 'Queue Size - After Album' ,
954+ 'Queue Size - After Album (verify no doubling) ' ,
825955 'size' ,
826956 validators . and (
827957 validators . responseCount ( 1 , 2 ) ,
828- validators . queueSizeIncreaseFrom ( 'beforeAlbum' , 1 ) ,
958+ validators . queueSizeIncreasedByStoredCount ( 'beforeAlbum' , 'abbeyRoadTracks' , 20 ) ,
829959 validators . recordQueueSize ( 'beforePlaylist' )
830960 ) ,
831961 4
832962 ) ,
833963
964+ // Search playlist first to get track count
965+ new TestCase (
966+ 'Search Playlist - Rock Classics (get track count)' ,
967+ 'searchplaylist rock classics' ,
968+ validators . and (
969+ validators . responseCount ( 1 , 2 ) ,
970+ validators . matchesRegex ( / p l a y l i s t | t r a c k s | \d + / i) ,
971+ validators . extractAndStoreTrackCount ( 'rockClassicsTracks' )
972+ ) ,
973+ 5
974+ ) ,
975+
834976 new TestCase (
835977 'Add Playlist - Rock Classics' ,
836978 'addplaylist rock classics' ,
@@ -845,12 +987,13 @@ const testSuiteArray = [
845987 12
846988 ) ,
847989
990+ // Verify playlist tracks added (not doubled!)
848991 new TestCase (
849- 'Queue Size - After Playlist' ,
992+ 'Queue Size - After Playlist (verify no doubling) ' ,
850993 'size' ,
851994 validators . and (
852995 validators . responseCount ( 1 , 2 ) ,
853- validators . queueSizeIncreaseFrom ( 'beforePlaylist' , 1 )
996+ validators . queueSizeIncreasedByStoredCount ( 'beforePlaylist' , 'rockClassicsTracks' , 20 )
854997 ) ,
855998 4
856999 ) ,
0 commit comments