@@ -186,8 +186,8 @@ async function openMidiStudio(page, routePayload = validManifest, midiRoutes = {
186186
187187async function fillGuidedSongSheet ( page , { intro = "Am F" , key = "A minor" , loop = "Am F C G" , style = "retro-arcade" , tempo = "132" } = { } ) {
188188 await page . locator ( "#songSheetTempoInput" ) . fill ( tempo ) ;
189- await page . locator ( "#songSheetKeyInput" ) . fill ( key ) ;
190- await page . locator ( "#songSheetStyleInput" ) . fill ( style ) ;
189+ await page . locator ( "#songSheetKeyInput" ) . selectOption ( key ) ;
190+ await page . locator ( "#songSheetStyleInput" ) . selectOption ( style ) ;
191191 await page . locator ( "#songSheetIntroInput" ) . fill ( intro ) ;
192192 await page . locator ( "#songSheetLoopInput" ) . fill ( loop ) ;
193193}
@@ -245,12 +245,71 @@ test.describe("MIDI Studio V2", () => {
245245 }
246246 } ) ;
247247
248+ test ( "shows guided visible options and how-to-test steps" , async ( { page } ) => {
249+ const server = await openMidiStudio ( page ) ;
250+ try {
251+ await expect ( page . locator ( "#songSheetKeyInput option" ) ) . toContainText ( [ "Choose key" , "A minor" , "C major" , "D minor" , "E minor" , "G major" ] ) ;
252+ await expect ( page . locator ( "#songSheetStyleInput option" ) ) . toContainText ( [ "Choose style" , "retro-arcade" , "chip" , "orchestral-boss" , "ambient-loop" , "victory-fanfare" ] ) ;
253+ await expect ( page . locator ( "#instrumentGridSubdivisionInput option" ) ) . toContainText ( [ "1/1" , "1/2" , "1/4" , "1/8" , "1/16" ] ) ;
254+ await expect ( page . locator ( "#instrumentGridLaneTypeSelect option" ) ) . toContainText ( [ "Chords" , "Bass" , "Pad" , "Lead" , "Drums" ] ) ;
255+ await expect ( page . locator ( "#renderedExportTargetTypeSelect option" ) ) . toContainText ( [ "WAV" , "MP3" , "OGG" ] ) ;
256+ await expect ( page . locator ( "#instrumentGridSectionSelect" ) ) . toContainText ( "No section selected" ) ;
257+ await expect ( page . locator ( "#instrumentGridTransportState" ) ) . toContainText ( "No section selected. Normalize grid data before testing section timing." ) ;
258+ await expect ( page . locator ( "#howToTestContent" ) ) . toContainText ( "Step 1: choose style/key/tempo" ) ;
259+ await expect ( page . locator ( "#howToTestContent" ) ) . toContainText ( "Step 6: test export action status" ) ;
260+ } finally {
261+ await workspaceV2CoverageReporter . stop ( page ) ;
262+ await server . close ( ) ;
263+ }
264+ } ) ;
265+
266+ test ( "loads explicit demo test song data for UAT grid and timing preview" , async ( { page } ) => {
267+ const server = await openMidiStudio ( page ) ;
268+ try {
269+ await page . locator ( "#useExampleButton" ) . click ( ) ;
270+ await expect ( page . locator ( "#songList" ) ) . toContainText ( "Demo Test Song" ) ;
271+ await expect ( page . locator ( "#songList" ) ) . toContainText ( "Demo Missing Target" ) ;
272+ await expect ( page . locator ( "#songSheetKeyInput" ) ) . toHaveValue ( "A minor" ) ;
273+ await expect ( page . locator ( "#songSheetStyleInput" ) ) . toHaveValue ( "retro-arcade" ) ;
274+ await expect ( page . locator ( "#instrumentGridSectionsInput" ) ) . toHaveValue ( "intro:1, loop:1, victory:1" ) ;
275+ await expect ( page . locator ( "#instrumentGridChordsInput" ) ) . toHaveValue ( "Am F C G | Am F C G | C G F Am" ) ;
276+ 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 \. / ) ;
277+
278+ await page . locator ( "#generateBassFromChordsButton" ) . click ( ) ;
279+ await page . locator ( "#generatePadFromChordsButton" ) . click ( ) ;
280+ await page . locator ( "#generateArpeggioFromChordsButton" ) . click ( ) ;
281+ await page . locator ( "#generateBasicDrumsButton" ) . click ( ) ;
282+ await page . locator ( "#normalizeInstrumentGridButton" ) . click ( ) ;
283+ await expect ( page . locator ( "#instrumentGridOutput" ) ) . toContainText ( "victory" ) ;
284+ await expect ( page . locator ( ".midi-studio-v2__grid-cell--bar" ) ) . toHaveCount ( 3 ) ;
285+ await expect ( page . locator ( "#instrumentGridSectionSelect" ) ) . toContainText ( "victory" ) ;
286+ const demoModel = await page . evaluate ( ( ) => window . __midiStudioV2App . lastInstrumentGridResult ) ;
287+ expect ( demoModel ) . toMatchObject ( { barCount : 3 , ok : true } ) ;
288+ expect ( demoModel . timeline . some ( ( event ) => event . source === "generated" && event . lane === "bass" ) ) . toBe ( true ) ;
289+
290+ await page . locator ( "#instrumentGridLoopStartSelect" ) . selectOption ( "loop" ) ;
291+ await page . locator ( "#instrumentGridLoopEndSelect" ) . selectOption ( "victory" ) ;
292+ expect ( await page . locator ( ".midi-studio-v2__grid-cell--loop-region" ) . count ( ) ) . toBeGreaterThan ( 0 ) ;
293+ await page . locator ( "#playLoopButton" ) . click ( ) ;
294+ await expect ( page . locator ( "#statusLog" ) ) . toHaveValue ( / W A R N L i v e p l a y b a c k s y n t h e s i s n o t i m p l e m e n t e d \. P l a y i n g t i m i n g - p r e v i e w p l a y h e a d o n l y ; n o a u d i o p l a y b a c k w a s s t a r t e d \. / ) ;
295+ await expect ( page . locator ( "#instrumentGridTransportState" ) ) . toContainText ( "Playing loop timing preview: loop to victory" ) ;
296+ await page . locator ( "#exportOggButton" ) . click ( ) ;
297+ 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 \. / ) ;
298+ await page . locator ( '[data-song-id="demo-missing-target"]' ) . click ( ) ;
299+ await page . locator ( "#exportWavButton" ) . click ( ) ;
300+ 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 \. / ) ;
301+ } finally {
302+ await workspaceV2CoverageReporter . stop ( page ) ;
303+ await server . close ( ) ;
304+ }
305+ } ) ;
306+
248307 test ( "selects multiple songs and updates source, director, and rendered targets" , async ( { page } ) => {
249308 const server = await openMidiStudio ( page ) ;
250309 try {
251310 await page . locator ( '[data-song-id="combat-light"]' ) . click ( ) ;
252311 await expect ( page . locator ( '[data-song-id="combat-light"]' ) ) . toHaveAttribute ( "aria-pressed" , "true" ) ;
253- await expect ( page . locator ( "#songSourceField" ) ) . toHaveValue ( "missing sourceMidi " ) ;
312+ await expect ( page . locator ( "#songSourceField" ) ) . toHaveValue ( "No MIDI source declared. " ) ;
254313 await expect ( page . locator ( "#instrumentSetField" ) ) . toHaveValue ( "Combat GM" ) ;
255314 await expect ( page . locator ( "#renderedTargets" ) ) . toContainText ( "combat-light.mp3" ) ;
256315 await expect ( page . locator ( "#directorPanel" ) ) . toContainText ( "Short encounter loop." ) ;
@@ -448,7 +507,7 @@ test.describe("MIDI Studio V2", () => {
448507 await expect ( page . locator ( "#songSheetSummary" ) ) . not . toContainText ( "intro:" ) ;
449508 await expect ( page . locator ( "#statusLog" ) ) . toHaveValue ( / F A I L S o n g S h e e t r e j e c t e d : I n v a l i d t e m p o \/ B P M \. E n t e r a p o s i t i v e n u m b e r b e f o r e p a r s i n g t h e g u i d e d S o n g S h e e t \. / ) ;
450509 await page . locator ( "#songSheetTempoInput" ) . fill ( "132" ) ;
451- await page . locator ( "#songSheetKeyInput" ) . fill ( "" ) ;
510+ await page . locator ( "#songSheetKeyInput" ) . selectOption ( "" ) ;
452511 await page . locator ( "#parseSongSheetButton" ) . click ( ) ;
453512 await expect ( page . locator ( "#songSheetSummary" ) ) . toContainText ( "Missing key. Enter a key before parsing the guided Song Sheet." ) ;
454513 await expect ( page . locator ( "#songSheetSummary" ) ) . not . toContainText ( "loop:" ) ;
@@ -906,6 +965,11 @@ Am F`);
906965 try {
907966 await expect ( page . locator ( "#songList" ) ) . toContainText ( "No MIDI songs loaded." ) ;
908967 await expect ( page . locator ( "#playButton" ) ) . toBeDisabled ( ) ;
968+ await expect ( page . locator ( "#songDetails" ) ) . toContainText ( "No song selected" ) ;
969+ await expect ( page . locator ( "#instrumentGridOutput" ) ) . toContainText ( "No grid data normalized. Enter sections/chords or use the example test song, then choose Normalize Grid." ) ;
970+ await expect ( page . locator ( "#instrumentGridSectionSelect" ) ) . toContainText ( "No section selected" ) ;
971+ await expect ( page . locator ( "#songSourceField" ) ) . toHaveValue ( "No song selected" ) ;
972+ await expect ( page . locator ( "#renderedTargets" ) ) . toContainText ( "No rendered WAV target selected." ) ;
909973 await expect ( page . locator ( "#statusLog" ) ) . toHaveValue ( / F A I L M I D I S t u d i o V 2 p a y l o a d r e j e c t e d b e f o r e r e n d e r .* m u s i c \. s o n g s \[ 0 \] \. i d i s r e q u i r e d \. / ) ;
910974 await page . locator ( "#exportWavButton" ) . click ( ) ;
911975 await expect ( page . locator ( "#statusLog" ) ) . toHaveValue ( / F A I L M i s s i n g M I D I s o n g f o r W A V e x p o r t \. L o a d o r s e l e c t a s o n g b e f o r e e x p o r t i n g \. / ) ;
0 commit comments