@@ -450,4 +450,138 @@ describe("RhythmBlocks", () => {
450450 expect ( block . hidden ) . toBe ( true ) ;
451451 } ) ;
452452 } ) ;
453+
454+ describe ( "Edge Cases and Additional Coverage" , ( ) => {
455+ test ( "MyNoteValueBlock handles undefined connections gracefully" , ( ) => {
456+ activity . blocks . blockList [ 1 ] = { connections : undefined } ;
457+ global . Singer . RhythmActions . getNoteValue . mockReturnValue ( 0 ) ;
458+
459+ const block = getBlock ( "mynotevalue" ) ;
460+ const result = block . arg ( logo , 0 , 1 ) ;
461+
462+ expect ( result ) . toBe ( 0 ) ;
463+ } ) ;
464+
465+ test ( "SkipNotesBlock handles zero skip value" , ( ) => {
466+ turtle . singer . skipFactor = 0 ;
467+ const block = getBlock ( "skipnotes" ) ;
468+ block . flow ( [ 0 , true ] , logo , 0 , 10 ) ;
469+
470+ expect ( turtle . singer . skipFactor ) . toBe ( 0 ) ;
471+ } ) ;
472+
473+ test ( "SkipNotesBlock handles negative skip value" , ( ) => {
474+ turtle . singer . skipFactor = 0 ;
475+ const block = getBlock ( "skipnotes" ) ;
476+ block . flow ( [ - 5 , true ] , logo , 0 , 10 ) ;
477+
478+ expect ( turtle . singer . skipFactor ) . toBe ( - 5 ) ;
479+ } ) ;
480+
481+ test ( "MultiplyBeatFactorBlock handles fractional factor" , ( ) => {
482+ const block = getBlock ( "multiplybeatfactor" ) ;
483+ block . flow ( [ 0.5 , true ] , logo , 0 , 10 ) ;
484+
485+ expect ( global . Singer . RhythmActions . multiplyNoteValue ) . toHaveBeenCalledWith ( 0.5 , 0 , 10 ) ;
486+ } ) ;
487+
488+ test ( "RhythmicDotBlock handles single dot" , ( ) => {
489+ const block = getBlock ( "rhythmicdot" ) ;
490+ block . flow ( [ true ] , logo , 0 , 10 ) ;
491+
492+ expect ( global . Singer . RhythmActions . doRhythmicDot ) . toHaveBeenCalledWith ( 1 , 0 , 10 ) ;
493+ } ) ;
494+
495+ test ( "RhythmicDot2Block handles multiple dots" , ( ) => {
496+ const block = getBlock ( "rhythmicdot2" ) ;
497+ block . flow ( [ 3 , true ] , logo , 0 , 10 ) ;
498+
499+ expect ( global . Singer . RhythmActions . doRhythmicDot ) . toHaveBeenCalledWith ( 3 , 0 , 10 ) ;
500+ } ) ;
501+
502+ test ( "NewNoteBlock registers correctly" , ( ) => {
503+ const block = getBlock ( "newnote" ) ;
504+ expect ( block ) . toBeDefined ( ) ;
505+ expect ( block . formDefn . args ) . toBe ( 2 ) ;
506+ } ) ;
507+
508+ test ( "NoteBlock macros are defined" , ( ) => {
509+ const noteBlocks = [ "note1" , "note2" , "note3" , "note4" , "note5" , "note6" , "note7" , "note8" ] ;
510+ noteBlocks . forEach ( blockName => {
511+ const block = getBlock ( blockName ) ;
512+ expect ( block ) . toBeDefined ( ) ;
513+ expect ( block . macro ) . toBeDefined ( ) ;
514+ } ) ;
515+ } ) ;
516+
517+ test ( "OctaveSpaceBlock is defined" , ( ) => {
518+ const block = getBlock ( "octavespace" ) ;
519+ expect ( block ) . toBeDefined ( ) ;
520+ } ) ;
521+
522+ test ( "DefineFrequencyBlock is defined" , ( ) => {
523+ const block = getBlock ( "definefrequency" ) ;
524+ expect ( block ) . toBeDefined ( ) ;
525+ } ) ;
526+
527+ test ( "All rhythm blocks have proper palette assignment" , ( ) => {
528+ const rhythmBlockNames = [
529+ "mynotevalue" , "skipfactor" , "osctime" , "swing" , "newswing" ,
530+ "newswing2" , "skipnotes" , "multiplybeatfactor" , "tie" ,
531+ "rhythmicdot" , "rhythmicdot2" , "rest2" , "note" , "newnote"
532+ ] ;
533+
534+ rhythmBlockNames . forEach ( blockName => {
535+ const block = activity . registeredBlocks [ blockName ] ;
536+ if ( block ) {
537+ expect ( block . palette ) . toBe ( "rhythm" ) ;
538+ }
539+ } ) ;
540+ } ) ;
541+
542+ test ( "Flow blocks return correct tuple format" , ( ) => {
543+ const flowBlocks = [ "swing" , "newswing2" , "skipnotes" , "multiplybeatfactor" , "tie" ] ;
544+
545+ flowBlocks . forEach ( blockName => {
546+ const block = getBlock ( blockName ) ;
547+ if ( block && block . flow ) {
548+ const result = block . flow ( [ 1 , true ] , logo , 0 , 10 ) ;
549+ if ( result ) {
550+ expect ( Array . isArray ( result ) ) . toBe ( true ) ;
551+ expect ( result . length ) . toBe ( 2 ) ;
552+ }
553+ }
554+ } ) ;
555+ } ) ;
556+ } ) ;
557+
558+ describe ( "Error Handling" , ( ) => {
559+ test ( "handles logo with missing statusFields" , ( ) => {
560+ logo . inStatusMatrix = true ;
561+ logo . statusFields = undefined ;
562+ activity . blocks . blockList [ 1 ] = { connections : [ 2 ] } ;
563+ activity . blocks . blockList [ 2 ] = { name : "print" } ;
564+
565+ const block = getBlock ( "mynotevalue" ) ;
566+ expect ( ( ) => block . arg ( logo , 0 , 1 ) ) . not . toThrow ( ) ;
567+ } ) ;
568+
569+ test ( "handles turtle with missing singer object" , ( ) => {
570+ activity . turtles . ithTurtle = jest . fn ( ( ) => ( { } ) ) ;
571+ activity . blocks . blockList [ 1 ] = { connections : [ 0 ] } ;
572+
573+ const block = getBlock ( "skipfactor" ) ;
574+ expect ( ( ) => block . arg ( logo , 0 , 1 ) ) . not . toThrow ( ) ;
575+ } ) ;
576+
577+ test ( "handles null blockList entries" , ( ) => {
578+ activity . blocks . blockList = { 0 : null , 1 : null } ;
579+ global . Singer . RhythmActions . getNoteValue . mockReturnValue ( 0 ) ;
580+
581+ const block = getBlock ( "mynotevalue" ) ;
582+ const result = block . arg ( logo , 0 , 1 ) ;
583+
584+ expect ( result ) . toBe ( 0 ) ;
585+ } ) ;
586+ } ) ;
453587} ) ;
0 commit comments