@@ -379,27 +379,37 @@ test.describe("MIDI Studio V2", () => {
379379 }
380380 } ) ;
381381
382- test ( "loads explicit demo test song data for UAT grid and Preview Synth timing preview" , async ( { page } ) => {
382+ test ( "loads explicit Twinkle Twinkle Little Star test song data for UAT note table and Preview Synth timing preview" , async ( { page } ) => {
383383 const server = await openMidiStudio ( page ) ;
384384 try {
385385 await page . locator ( "#useExampleButton" ) . click ( ) ;
386- await expect ( page . locator ( "#songList" ) ) . toContainText ( "Demo Test Song " ) ;
386+ await expect ( page . locator ( "#songList" ) ) . toContainText ( "Twinkle Twinkle Little Star " ) ;
387387 await expect ( page . locator ( "#songList" ) ) . toContainText ( "Demo Missing Target" ) ;
388- await expect ( page . locator ( "#songSheetKeyInput" ) ) . toHaveValue ( "A minor " ) ;
389- await expect ( page . locator ( "#songSheetStyleInput" ) ) . toHaveValue ( "retro-arcade " ) ;
390- await expect ( page . locator ( "#instrumentGridSectionsInput" ) ) . toHaveValue ( "intro:1 , loop:1, victory:1 " ) ;
391- await expect ( page . locator ( "#instrumentGridChordsInput" ) ) . toHaveValue ( "Am F C G | Am F C G | C G F Am " ) ;
388+ await expect ( page . locator ( "#songSheetKeyInput" ) ) . toHaveValue ( "C major " ) ;
389+ await expect ( page . locator ( "#songSheetStyleInput" ) ) . toHaveValue ( "chip " ) ;
390+ await expect ( page . locator ( "#instrumentGridSectionsInput" ) ) . toHaveValue ( "intro:2 , loop:2 " ) ;
391+ await expect ( page . locator ( "#instrumentGridChordsInput" ) ) . toHaveValue ( "C C G G | F F C C | F F C C | G G C C " ) ;
392392 await expect ( page . locator ( "#previewInstrumentLeadSelect" ) ) . toHaveValue ( "retro-pulse-lead" ) ;
393393 await expect ( page . locator ( "#previewInstrumentPadSelect" ) ) . toHaveValue ( "ambient-pad" ) ;
394- await expect ( page . locator ( "#statusLog" ) ) . toHaveValue ( / O K L o a d e d e x p l i c i t d e m o t e s t s o n g d a t a \. D e m o p a t h s a r e d e c l a r e d f o r U A T o n l y ; t h e y a r e n o t h i d d e n f a l l b a c k a s s e t s \. / ) ;
394+ await expect ( page . locator ( "#statusLog" ) ) . toHaveValue ( / O K L o a d e d e x p l i c i t T w i n k l e T w i n k l e L i t t l e S t a r t e s t s o n g d a t a \. D e m o p a t h s a r e d e c l a r e d f o r U A T o n l y ; t h e y a r e n o t h i d d e n f a l l b a c k a s s e t s \. / ) ;
395395 await expect ( page . locator ( "#instrumentGridSectionSelect" ) ) . toContainText ( "intro" ) ;
396- await expect ( page . locator ( ".midi-studio-v2__grid-cell" ) . first ( ) ) . toHaveText ( "Instrument/Lane" ) ;
397- await expect ( page . locator ( ".midi-studio-v2__spreadsheet-note-cell[data-lane]" ) ) . not . toHaveCount ( 0 ) ;
398- await expect ( spreadsheetCell ( page , "chords" , 0 ) ) . toHaveText ( "Am" ) ;
399- await expect ( spreadsheetCell ( page , "bass" , 0 ) ) . toHaveText ( "A2" ) ;
400- await expect ( spreadsheetCell ( page , "pad" , 0 ) ) . toHaveText ( "Am" ) ;
401- await expect ( spreadsheetCell ( page , "lead" , 0 ) ) . toHaveText ( "A4" ) ;
396+ await expect ( page . locator ( ".midi-studio-v2__note-table" ) ) . toHaveCount ( 1 ) ;
397+ await expect ( page . locator ( ".midi-studio-v2__grid-cell" ) . first ( ) ) . toHaveText ( "Instrument" ) ;
398+ await expect ( page . locator ( ".midi-studio-v2__note-table-column-header" ) . first ( ) ) . toContainText ( "Bar 1" ) ;
399+ await expect ( page . locator ( ".midi-studio-v2__note-table-cell[data-lane]" ) ) . not . toHaveCount ( 0 ) ;
400+ await expect ( page . locator ( "#instrumentGridOutput textarea" ) ) . toHaveCount ( 0 ) ;
401+ await expect ( page . locator ( ".midi-studio-v2__lane-header-cell strong" ) ) . toContainText ( [ "Chords" , "Bass" , "Pad" , "Lead" , "Drums" ] ) ;
402+ expect ( await page . evaluate ( ( ) => {
403+ const output = document . querySelector ( "#instrumentGridOutput" ) ;
404+ const sourceInputs = document . querySelector ( ".midi-studio-v2__grid-lane-inputs--source" ) ;
405+ return Boolean ( output && sourceInputs && ( output . compareDocumentPosition ( sourceInputs ) & Node . DOCUMENT_POSITION_FOLLOWING ) ) ;
406+ } ) ) . toBe ( true ) ;
407+ await expect ( spreadsheetCell ( page , "chords" , 0 ) ) . toHaveText ( "C" ) ;
408+ await expect ( spreadsheetCell ( page , "bass" , 0 ) ) . toHaveText ( "C2" ) ;
409+ await expect ( spreadsheetCell ( page , "pad" , 0 ) ) . toHaveText ( "C" ) ;
410+ await expect ( spreadsheetCell ( page , "lead" , 0 ) ) . toHaveText ( "C4" ) ;
402411 await expect ( spreadsheetCell ( page , "drums" , 0 ) ) . toHaveText ( "kick" ) ;
412+ expect ( await page . locator ( "#instrumentGridOutput" ) . evaluate ( ( output ) => ! output . contains ( document . querySelector ( "#audioDiagnostics" ) ) ) ) . toBe ( true ) ;
403413 await page . locator ( "#playSectionButton" ) . click ( ) ;
404414 await expect ( page . locator ( "#statusLog" ) ) . toHaveValue ( / O K P r e v i e w S y n t h s t a r t e d f o r s e c t i o n i n t r o w i t h \d + p l a y a b l e e v e n t s \. / ) ;
405415 expect ( await page . evaluate ( ( ) => window . __midiStudioPreviewSynthEvents . some ( ( event ) => event . action === "oscillator-start" ) ) ) . toBe ( true ) ;
@@ -410,24 +420,23 @@ test.describe("MIDI Studio V2", () => {
410420 await page . locator ( "#generateArpeggioFromChordsButton" ) . click ( ) ;
411421 await page . locator ( "#generateBasicDrumsButton" ) . click ( ) ;
412422 await page . locator ( "#normalizeInstrumentGridButton" ) . click ( ) ;
413- await expect ( page . locator ( "#instrumentGridOutput" ) ) . toContainText ( "victory" ) ;
414- await expect ( page . locator ( ".midi-studio-v2__grid-cell--bar" ) ) . toHaveCount ( 3 ) ;
415- await expect ( page . locator ( "#instrumentGridSectionSelect" ) ) . toContainText ( "victory" ) ;
423+ await expect ( page . locator ( ".midi-studio-v2__grid-cell--bar" ) ) . toHaveCount ( 4 ) ;
424+ await expect ( page . locator ( "#instrumentGridSectionSelect" ) ) . toContainText ( "loop" ) ;
416425 const demoModel = await page . evaluate ( ( ) => window . __midiStudioV2App . lastInstrumentGridResult ) ;
417- expect ( demoModel ) . toMatchObject ( { barCount : 3 , ok : true } ) ;
418- expect ( demoModel . timeline . some ( ( event ) => event . source === "generated " && event . lane === "bass " ) ) . toBe ( true ) ;
426+ expect ( demoModel ) . toMatchObject ( { barCount : 4 , ok : true } ) ;
427+ expect ( demoModel . timeline . some ( ( event ) => event . lane === "lead " && event . value === "C4 " ) ) . toBe ( true ) ;
419428
420- await page . locator ( "#instrumentGridLoopStartSelect" ) . selectOption ( "loop " ) ;
421- await page . locator ( "#instrumentGridLoopEndSelect" ) . selectOption ( "victory " ) ;
429+ await page . locator ( "#instrumentGridLoopStartSelect" ) . selectOption ( "intro " ) ;
430+ await page . locator ( "#instrumentGridLoopEndSelect" ) . selectOption ( "loop " ) ;
422431 expect ( await page . locator ( ".midi-studio-v2__grid-cell--loop-region" ) . count ( ) ) . toBeGreaterThan ( 0 ) ;
423432 await page . locator ( "#playLoopButton" ) . click ( ) ;
424- await expect ( page . locator ( "#statusLog" ) ) . toHaveValue ( / O K P r e v i e w S y n t h s t a r t e d f o r l o o p l o o p t o v i c t o r y w i t h \d + p l a y a b l e e v e n t s \. / ) ;
433+ await expect ( page . locator ( "#statusLog" ) ) . toHaveValue ( / O K P r e v i e w S y n t h s t a r t e d f o r l o o p i n t r o t o l o o p w i t h \d + p l a y a b l e e v e n t s \. / ) ;
425434 await expect ( page . locator ( "#statusLog" ) ) . toHaveValue ( / P r e v i e w S y n t h u s e s t e m p o r a r y o s c i l l a t o r i n s t r u m e n t s f o r g r i d a u d i t i o n o n l y ; S o u n d F o n t p l a y b a c k i s n o t i m p l e m e n t e d \. / ) ;
426- await expect ( page . locator ( "#instrumentGridTransportState" ) ) . toContainText ( "Playing loop Preview Synth timing preview: loop to victory " ) ;
435+ await expect ( page . locator ( "#instrumentGridTransportState" ) ) . toContainText ( "Playing loop Preview Synth timing preview: intro to loop " ) ;
427436 expect ( await page . evaluate ( ( ) => window . __midiStudioPreviewSynthEvents . some ( ( event ) => event . action === "oscillator-start" ) ) ) . toBe ( true ) ;
428437 await expect ( page . locator ( ".midi-studio-v2__grid-cell--lane-active" ) ) . not . toHaveCount ( 0 ) ;
429438 await page . locator ( "#exportOggButton" ) . click ( ) ;
430- await expect ( page . locator ( "#statusLog" ) ) . toHaveValue ( / W A R N E x p o r t r e n d e r i n g n o t i m p l e m e n t e d f o r O G G \. P l a n n e d t a r g e t : a s s e t s \/ m u s i c \/ d e m o \/ d e m o - t e s t - s o n g \. o g g \. / ) ;
439+ await expect ( page . locator ( "#statusLog" ) ) . toHaveValue ( / W A R N E x p o r t r e n d e r i n g n o t i m p l e m e n t e d f o r O G G \. P l a n n e d t a r g e t : a s s e t s \/ m u s i c \/ d e m o \/ t w i n k l e - t w i n k l e - l i t t l e - s t a r \. o g g \. / ) ;
431440 await page . locator ( '[data-song-id="demo-missing-target"]' ) . click ( ) ;
432441 await page . locator ( "#exportWavButton" ) . click ( ) ;
433442 await expect ( page . locator ( "#statusLog" ) ) . toHaveValue ( / F A I L M i s s i n g r e n d e r e d W A V e x p o r t t a r g e t f o r D e m o M i s s i n g T a r g e t \. A d d m u s i c \. s o n g s \[ \] \. r e n d e r e d \. w a v b e f o r e e x p o r t i n g \. / ) ;
@@ -442,23 +451,23 @@ test.describe("MIDI Studio V2", () => {
442451 try {
443452 await page . locator ( "#loadExampleAndPlayButton" ) . click ( ) ;
444453 await expect ( page . locator ( "#statusLog" ) ) . toHaveValue ( / O K L o a d E x a m p l e A n d P l a y s t a r t e d \. / ) ;
445- await expect ( page . locator ( "#statusLog" ) ) . toHaveValue ( / O K L o a d E x a m p l e A n d P l a y l o a d e d e x p l i c i t d e m o d a t a \. / ) ;
454+ await expect ( page . locator ( "#statusLog" ) ) . toHaveValue ( / O K L o a d E x a m p l e A n d P l a y l o a d e d e x p l i c i t T w i n k l e T w i n k l e L i t t l e S t a r d a t a \. / ) ;
446455 await expect ( page . locator ( "#statusLog" ) ) . toHaveValue ( / O K L o a d E x a m p l e A n d P l a y a s s i g n e d P r e v i e w S y n t h i n s t r u m e n t s \. / ) ;
447- await expect ( page . locator ( "#statusLog" ) ) . toHaveValue ( / O K D e m o g r i d h a s \d + p l a y a b l e P r e v i e w S y n t h n o t e s a f t e r l a n e g e n e r a t i o n \. / ) ;
456+ await expect ( page . locator ( "#statusLog" ) ) . toHaveValue ( / O K T w i n k l e g r i d h a s \d + p l a y a b l e P r e v i e w S y n t h n o t e s a f t e r l a n e g e n e r a t i o n \. / ) ;
448457 await expect ( page . locator ( "#statusLog" ) ) . toHaveValue ( / O K P r e v i e w S y n t h s t a r t e d f o r s e c t i o n i n t r o w i t h \d + p l a y a b l e e v e n t s \. / ) ;
449458 await expect ( page . locator ( "#statusLog" ) ) . toHaveValue ( / O K L o a d E x a m p l e A n d P l a y s t a r t e d a u d i b l e P r e v i e w S y n t h p l a y b a c k a n d m o v e d t h e p l a y h e a d \. / ) ;
450459 await expect ( page . locator ( "#instrumentGridTransportState" ) ) . toContainText ( "Playing section Preview Synth timing preview: intro" ) ;
451460 expect ( await page . evaluate ( ( ) => window . __midiStudioPreviewSynthEvents . some ( ( event ) => event . action === "resume" ) ) ) . toBe ( true ) ;
452461 expect ( await page . evaluate ( ( ) => window . __midiStudioPreviewSynthEvents . some ( ( event ) => event . action === "oscillator-start" ) ) ) . toBe ( true ) ;
453462 await expect ( page . locator ( ".midi-studio-v2__grid-cell--timing-header.midi-studio-v2__grid-cell--playhead-active" ) ) . not . toHaveAttribute ( "data-step-index" , "0" ) ;
454- await expect ( spreadsheetCell ( page , "bass" , 0 ) ) . toHaveText ( "A2 " ) ;
463+ await expect ( spreadsheetCell ( page , "bass" , 0 ) ) . toHaveText ( "C2 " ) ;
455464 const diagnostics = await audioDiagnosticsRows ( page ) ;
456465 expect ( Number ( diagnostics [ "Playable note count" ] ) ) . toBeGreaterThan ( 0 ) ;
457466 expect ( diagnostics ) . toMatchObject ( {
458467 "Audio context state" : "running" ,
459468 "Last playback error" : "none" ,
460469 "Selected section" : "intro" ,
461- "Selected song" : "Demo Test Song "
470+ "Selected song" : "Twinkle Twinkle Little Star "
462471 } ) ;
463472 expect ( diagnostics [ "Active lanes" ] ) . toMatch ( / b a s s | c h o r d s | d r u m s | l e a d | p a d / ) ;
464473 expect ( diagnostics [ "Current preview instrument pack" ] ) . toContain ( "lead: Retro Pulse Lead" ) ;
@@ -739,8 +748,8 @@ Am F`);
739748 await page . locator ( "#normalizeInstrumentGridButton" ) . click ( ) ;
740749 await expect ( page . locator ( "#instrumentGridSummary" ) ) . toContainText ( "intro: 1 bar; loop: 1 bar" ) ;
741750 await expect ( page . locator ( "#instrumentGridSummary" ) ) . toContainText ( "30 normalized events" ) ;
742- await expect ( page . locator ( "#instrumentGridOutput" ) ) . toContainText ( "intro" ) ;
743- await expect ( page . locator ( "#instrumentGridOutput" ) ) . toContainText ( "loop" ) ;
751+ await expect ( page . locator ( "#instrumentGridOutput" ) ) . not . toContainText ( "intro" ) ;
752+ await expect ( page . locator ( "#instrumentGridOutput" ) ) . not . toContainText ( "loop" ) ;
744753 await expect ( page . locator ( "#instrumentGridOutput" ) ) . toContainText ( "Am" ) ;
745754 await expect ( page . locator ( "#instrumentGridOutput" ) ) . toContainText ( "A2" ) ;
746755 await expect ( page . locator ( "#instrumentGridOutput" ) ) . toContainText ( "kick" ) ;
@@ -804,16 +813,16 @@ Am F`);
804813 } ) ;
805814 await page . locator ( "#normalizeInstrumentGridButton" ) . click ( ) ;
806815 expect ( await page . locator ( ".midi-studio-v2__instrument-grid" ) . evaluate ( ( grid ) => getComputedStyle ( grid ) . gridTemplateColumns . split ( " " ) . length ) ) . toBe ( 9 ) ;
807- await expect ( page . locator ( ".midi-studio-v2__grid-cell" ) . first ( ) ) . toHaveText ( "Instrument/Lane " ) ;
816+ await expect ( page . locator ( ".midi-studio-v2__grid-cell" ) . first ( ) ) . toHaveText ( "Instrument" ) ;
808817 expect ( await page . locator ( ".midi-studio-v2__grid-cell--timing-header" ) . evaluateAll ( ( cells ) => cells . map ( ( cell ) => cell . textContent ) ) ) . toEqual ( [
809- "Section introBar 1Beat 1" ,
810- "Section introBar 1Beat 2" ,
811- "Section introBar 1Beat 3" ,
812- "Section introBar 1Beat 4" ,
813- "Section loopBar 2Beat 1" ,
814- "Section loopBar 2Beat 2" ,
815- "Section loopBar 2Beat 3" ,
816- "Section loopBar 2Beat 4"
818+ "Bar 1Beat 1" ,
819+ "Bar 1Beat 2" ,
820+ "Bar 1Beat 3" ,
821+ "Bar 1Beat 4" ,
822+ "Bar 2Beat 1" ,
823+ "Bar 2Beat 2" ,
824+ "Bar 2Beat 3" ,
825+ "Bar 2Beat 4"
817826 ] ) ;
818827 await expect ( spreadsheetCell ( page , "chords" , 0 ) ) . toHaveText ( "Am" ) ;
819828 await expect ( spreadsheetCell ( page , "bass" , 0 ) ) . toHaveText ( "A2" ) ;
@@ -854,7 +863,8 @@ Am F`);
854863 await fillInstrumentGrid ( page , { drums : "kick zap snare hat | kick hat snare hat" } ) ;
855864 await page . locator ( "#normalizeInstrumentGridButton" ) . click ( ) ;
856865 await expect ( page . locator ( "#instrumentGridSummary" ) ) . toContainText ( 'Invalid drum token "zap"' ) ;
857- await expect ( page . locator ( "#instrumentGridOutput" ) ) . toContainText ( "intro" ) ;
866+ await expect ( page . locator ( "#instrumentGridSummary" ) ) . toContainText ( "intro: 1 bar; loop: 1 bar" ) ;
867+ await expect ( page . locator ( "#instrumentGridOutput" ) ) . not . toContainText ( "intro" ) ;
858868 await expect ( page . locator ( "#statusLog" ) ) . toHaveValue ( / W A R N I n s t r u m e n t g r i d n o r m a l i z e d w i t h w a r n i n g s : I n v a l i d d r u m t o k e n " z a p " a t b a r 1 , b e a t 2 ; t o k e n w a s s k i p p e d \. / ) ;
859869 await expect ( page . locator ( "#statusLog" ) ) . toHaveValue ( / O K I n s t r u m e n t g r i d n o r m a l i z e d : 2 s e c t i o n s , 2 b a r s , 2 9 e v e n t s \. / ) ;
860870 } finally {
@@ -880,10 +890,10 @@ Am F`);
880890 await page . locator ( "#normalizeInstrumentGridButton" ) . click ( ) ;
881891 expect ( await page . locator ( ".midi-studio-v2__instrument-grid" ) . evaluate ( ( grid ) => getComputedStyle ( grid ) . gridTemplateColumns . split ( " " ) . length ) ) . toBe ( 5 ) ;
882892 expect ( await page . locator ( ".midi-studio-v2__grid-cell--timing-header" ) . evaluateAll ( ( cells ) => cells . map ( ( cell ) => cell . textContent ) ) ) . toEqual ( [
883- "Section introBar 1Beat 1Subdivision 1" ,
884- "Section introBar 1Beat 1Subdivision 2" ,
885- "Section introBar 1Beat 2Subdivision 1" ,
886- "Section introBar 1Beat 2Subdivision 2"
893+ "Bar 1Beat 1Subdivision 1" ,
894+ "Bar 1Beat 1Subdivision 2" ,
895+ "Bar 1Beat 2Subdivision 1" ,
896+ "Bar 1Beat 2Subdivision 2"
887897 ] ) ;
888898 await page . locator ( "#instrumentGridSubdivisionInput" ) . selectOption ( "16" ) ;
889899 await expect ( page . locator ( "#instrumentGridSnapIndicator" ) ) . toContainText ( "Snap: 1 bar / 2 beats / 1/16" ) ;
0 commit comments