@@ -2466,6 +2466,106 @@ test.describe("MIDI Studio V2", () => {
24662466 }
24672467 } ) ;
24682468
2469+ test ( "keeps Export tab usable while rendered audio export remains planned" , async ( { page } ) => {
2470+ let server = await openMidiStudio ( page ) ;
2471+ try {
2472+ await expect ( page . locator ( '.midi-studio-v2__tool-menu #renderedExportTargetTypeSelect' ) ) . toHaveCount ( 0 ) ;
2473+ await expect ( page . locator ( '.midi-studio-v2__tool-menu #renderedExportSaveButton' ) ) . toHaveCount ( 0 ) ;
2474+ await selectMidiStudioTab ( page , "export" ) ;
2475+ await expect ( page . locator ( "#exportOutputTypeSection" ) ) . toContainText ( "Output Type" ) ;
2476+ await expect ( page . locator ( "#exportRenderSourceSection" ) ) . toContainText ( "Render Source" ) ;
2477+ await expect ( page . locator ( '.accordion-v2__header[aria-controls="renderedTargetsContent"]' ) ) . toContainText ( "Output Targets" ) ;
2478+ await expect ( page . locator ( "#futureExportOptionsSection" ) ) . toContainText ( "Future Rendering Options" ) ;
2479+ await expect ( page . locator ( "#exportStatusSection" ) ) . toContainText ( "Export Status" ) ;
2480+ await expect ( page . locator ( "#renderedExportTargetTypeSelect option" ) ) . toContainText ( [ "WAV" , "MP3" , "OGG" ] ) ;
2481+ await expect ( page . locator ( "#renderedExportSaveButton" ) ) . toHaveText ( "Save/Export" ) ;
2482+ const exportControlOwners = await page . locator ( "#renderedExportTargetTypeSelect, #renderedExportSaveButton" ) . evaluateAll ( ( controls ) => controls . map ( ( control ) => control . closest ( "[data-midi-studio-tab-panel]" ) ?. dataset . midiStudioTabPanel ) ) ;
2483+ expect ( exportControlOwners ) . toEqual ( [ "export" , "export" ] ) ;
2484+
2485+ await expect ( page . locator ( "#exportRenderSource" ) ) . toContainText ( "Main Theme" ) ;
2486+ await expect ( page . locator ( "#exportRenderSource" ) ) . toContainText ( "canonical song model / octave timeline data" ) ;
2487+ await expect ( page . locator ( "#exportRenderSource" ) ) . toContainText ( "Playable event count" ) ;
2488+ expect ( await page . locator ( "#exportRenderSource dd" ) . nth ( 1 ) . textContent ( ) ) . toMatch ( / ^ \d + $ / ) ;
2489+ expect ( Number . isFinite ( await page . evaluate ( ( ) => window . __midiStudioV2App . playableEventSummary ( ) . count ) ) ) . toBe ( true ) ;
2490+
2491+ const targetOwnership = await page . locator ( "#renderedTargetWavInput, #renderedTargetMp3Input, #renderedTargetOggInput" ) . evaluateAll ( ( inputs ) => inputs . map ( ( input ) => ( {
2492+ disabled : input . disabled ,
2493+ id : input . id ,
2494+ panel : input . closest ( "[data-midi-studio-tab-panel]" ) ?. dataset . midiStudioTabPanel ,
2495+ value : input . value
2496+ } ) ) ) ;
2497+ expect ( targetOwnership ) . toEqual ( [
2498+ { disabled : false , id : "renderedTargetWavInput" , panel : "export" , value : "assets/music/rendered/theme-main.wav" } ,
2499+ { disabled : false , id : "renderedTargetMp3Input" , panel : "export" , value : "assets/music/rendered/theme-main.mp3" } ,
2500+ { disabled : false , id : "renderedTargetOggInput" , panel : "export" , value : "assets/music/rendered/theme-main.ogg" }
2501+ ] ) ;
2502+ await page . locator ( "#renderedTargetMp3Input" ) . fill ( "assets/music/rendered/custom-main.mp3" ) ;
2503+ expect ( await page . evaluate ( ( ) => window . __midiStudioV2App . selectedSong ( ) . rendered . mp3 ) ) . toBe ( "assets/music/rendered/custom-main.mp3" ) ;
2504+
2505+ await selectMidiStudioTab ( page , "diagnostics" ) ;
2506+ await expect ( page . locator ( "#renderedTargetDiagnosticsContent" ) ) . toBeVisible ( ) ;
2507+ await expect ( page . locator ( "#renderedTargetDiagnostics" ) ) . toContainText ( "assets/music/rendered/custom-main.mp3" ) ;
2508+ await expect ( page . locator ( "#renderedTargetDiagnostics input, #renderedTargetDiagnostics textarea, #renderedTargetDiagnostics select" ) ) . toHaveCount ( 0 ) ;
2509+ await expect ( page . locator ( "#renderedTargetsContent" ) ) . toBeHidden ( ) ;
2510+
2511+ await selectMidiStudioTab ( page , "export" ) ;
2512+ const futureControls = await page . locator ( "#futureExportOptionsSection [data-midi-studio-future-control]" ) . evaluateAll ( ( controls ) => controls . map ( ( control ) => ( {
2513+ disabled : control . disabled ,
2514+ status : control . dataset . midiStudioUnwired ,
2515+ text : control . textContent . trim ( ) ,
2516+ title : control . title
2517+ } ) ) ) ;
2518+ expect ( futureControls ) . toHaveLength ( 6 ) ;
2519+ expect ( futureControls . every ( ( control ) => control . disabled && control . status === "not-implemented" && control . title . includes ( "Not implemented:" ) ) ) . toBe ( true ) ;
2520+ expect ( futureControls . map ( ( control ) => control . text ) ) . toEqual ( expect . arrayContaining ( [
2521+ "SoundFont" ,
2522+ "Render Quality" ,
2523+ "Sample Rate" ,
2524+ "Normalize Volume" ,
2525+ "Export Stems" ,
2526+ "Loop Export"
2527+ ] ) ) ;
2528+
2529+ await page . locator ( "#renderedExportTargetTypeSelect" ) . selectOption ( "mp3" ) ;
2530+ await page . locator ( "#renderedExportSaveButton" ) . click ( ) ;
2531+ 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 M P 3 \. P l a n n e d t a r g e t : a s s e t s \/ m u s i c \/ r e n d e r e d \/ c u s t o m - m a i n \. m p 3 \. / ) ;
2532+ await expect ( page . locator ( "#statusLog" ) ) . not . toHaveValue ( / c r e a t e d .* c u s t o m - m a i n \. m p 3 | w r o t e .* c u s t o m - m a i n \. m p 3 | s a v e d .* c u s t o m - m a i n \. m p 3 / i) ;
2533+ await expect ( page . locator ( "#exportStatusDetails" ) ) . toContainText ( "WARN: Export rendering not implemented for MP3. Planned target: assets/music/rendered/custom-main.mp3." ) ;
2534+ expect ( await controlColors ( page , "#renderedExportSaveButton" ) ) . toMatchObject ( {
2535+ borderTopColor : "rgb(248, 113, 113)" ,
2536+ color : "rgb(254, 202, 202)"
2537+ } ) ;
2538+
2539+ await selectMidiStudioTab ( page , "studio" ) ;
2540+ await page . locator ( "#playButton" ) . click ( ) ;
2541+ await expect ( page . locator ( "#playButton" ) ) . toBeDisabled ( ) ;
2542+ await expect ( page . locator ( "#stopButton" ) ) . toBeEnabled ( ) ;
2543+ await page . locator ( "#stopButton" ) . click ( ) ;
2544+ await expect ( page . locator ( "#stopButton" ) ) . toBeDisabled ( ) ;
2545+ await expect ( page . locator ( "#playButton" ) ) . toBeEnabled ( ) ;
2546+ } finally {
2547+ await workspaceV2CoverageReporter . stop ( page ) ;
2548+ await server . close ( ) ;
2549+ }
2550+
2551+ server = await openMidiStudio ( page , {
2552+ music : {
2553+ version : 1 ,
2554+ songs : [ { name : "Broken Song" } ]
2555+ }
2556+ } ) ;
2557+ try {
2558+ await selectMidiStudioTab ( page , "export" ) ;
2559+ await page . locator ( "#renderedExportTargetTypeSelect" ) . selectOption ( "wav" ) ;
2560+ await page . locator ( "#renderedExportSaveButton" ) . click ( ) ;
2561+ 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 \. / ) ;
2562+ await expect ( page . locator ( "#exportStatusDetails" ) ) . toContainText ( "FAIL: Missing MIDI song for WAV export. Load or select a song before exporting." ) ;
2563+ } finally {
2564+ await workspaceV2CoverageReporter . stop ( page ) ;
2565+ await server . close ( ) ;
2566+ }
2567+ } ) ;
2568+
24692569 test ( "derives primary song, instrument, grid, playback, and diagnostics views from the canonical selected song" , async ( { page } ) => {
24702570 const server = await openMidiStudioForImport ( page ) ;
24712571 try {
@@ -2610,7 +2710,7 @@ test.describe("MIDI Studio V2", () => {
26102710 await expect ( page . locator ( "#playButton" ) ) . toHaveText ( "Play" ) ;
26112711 await expect ( page . locator ( "#inspectMidiSourceButton" ) ) . toBeEnabled ( ) ;
26122712 const renderedHeader = page . locator ( '.accordion-v2__header[aria-controls="renderedTargetsContent"]' ) ;
2613- await expect ( renderedHeader ) . toContainText ( "Rendered Export Targets" ) ;
2713+ await expect ( renderedHeader ) . toContainText ( "Output Targets" ) ;
26142714 await expect ( renderedHeader . locator ( "#exportWavButton" ) ) . toHaveCount ( 0 ) ;
26152715 await expect ( page . locator ( "#exportWavButton" ) ) . toHaveCount ( 0 ) ;
26162716 await expect ( page . locator ( "#exportMp3Button" ) ) . toHaveCount ( 0 ) ;
0 commit comments