feedBack-desktop/tests/renderer-capability-migration.test.js
2026-06-16 18:48:12 +02:00

126 lines
7.5 KiB
JavaScript

const test = require('node:test');
const assert = require('node:assert/strict');
const path = require('node:path');
const fs = require('node:fs');
const ROOT = path.join(__dirname, '..');
function readJson(relpath) {
return JSON.parse(fs.readFileSync(path.join(ROOT, relpath), 'utf8'));
}
function readText(relpath) {
return fs.readFileSync(path.join(ROOT, relpath), 'utf8');
}
test('renderer manifest declares active playback observer', () => {
const manifest = readJson('src/renderer/plugin.json');
const playback = manifest.capabilities.playback;
assert.deepEqual(playback.roles, ['observer']);
assert.equal(playback.kind, 'lifecycle');
assert.deepEqual(playback.observes, ['loading', 'ready', 'stopped', 'ended']);
assert.equal(playback.mode, 'active');
assert.equal(playback.compatibility, 'shim-allowed');
assert.equal(playback.ownership, 'observer-only');
assert.equal(playback.safety, 'safe');
assert.equal(playback.version, 1);
});
test('renderer uses playback lifecycle instead of global transport wrappers', () => {
const source = readText('src/renderer/screen.js');
assert.equal(source.includes('window.playSong ='), false);
assert.equal(source.includes('window.stopSong ='), false);
assert.equal(source.includes('registerObserver'), true);
assert.equal(source.includes("playback:loading"), true);
assert.equal(source.includes("playback:ready"), true);
assert.equal(source.includes("playback:stopped"), true);
assert.equal(source.includes("playback:ended"), true);
assert.equal(source.includes('settingsKey'), true);
assert.equal(source.includes('_slopsmithPlaybackSettingsKey'), true);
});
test('renderer migrates legacy filename tone mappings to playback settings key', () => {
const source = readText('src/renderer/screen.js');
const docs = readText('docs/CAPABILITY-MIGRATION.md');
assert.equal(source.includes('migrateToneMappingsToPlaybackSettingsKey'), true);
assert.equal(source.includes('window._aeMigrateToneMappingsToPlaybackSettingsKey'), true);
assert.equal(source.includes("migrateBucket('songs')"), true);
assert.equal(source.includes("migrateBucket('midiPC')"), true);
assert.equal(docs.includes('Automatic Migration For Existing Mappings'), true);
assert.equal(docs.includes('Existing `settingsKey` buckets win and are not overwritten.'), true);
});
test('renderer registers native audio-mix fader participants', () => {
const source = readText('src/renderer/screen.js');
assert.equal(source.includes('registerMixParticipant'), true);
assert.equal(source.includes('audio_engine.input_gain'), true);
assert.equal(source.includes('audio_engine.chain_gain'), true);
assert.equal(source.includes("'fader.get-value'"), true);
assert.equal(source.includes("'fader.set-value'"), true);
});
test('chain panel summarizes provider-managed audio effects mappings', () => {
const source = readText('src/renderer/screen.js');
assert.equal(source.includes('fetchAudioEffectMappingsForSong'), true);
assert.equal(source.includes('/api/audio-effects/mappings?'), true);
assert.equal(source.includes('summarizeProviderManagedMappings'), true);
assert.equal(source.includes('rig_builder.effects'), true);
assert.equal(source.includes('Chain Provider'), true);
assert.equal(source.includes('ae-open-rig-builder'), true);
assert.equal(source.includes('hasProviderManagedAudioEffectsChain'), true);
assert.equal(source.includes('window._aeHasProviderManagedChain'), true);
assert.equal(source.includes('function shouldShowPlayerChainButton()'), true);
assert.equal(source.includes("String(inspected?.providerId || '').trim() === 'nam-tone'"), true);
assert.equal(source.includes('window._aeShouldShowPlayerChainButton'), true);
assert.equal(source.includes('window._aeInjectPlayerToneButton = injectPlayerToneButton'), true);
assert.equal(source.includes('function rigBuilderToneOwnershipState()'), true);
assert.equal(source.includes("window.__rbMegaChainSetting === true"), true);
assert.equal(source.includes("state: pending ? 'selected' : failed ? 'fallback' : active ? 'loaded' : 'selected'"), true);
assert.equal(source.includes('function removePlayerChainButton()'), true);
assert.equal(source.includes("document.getElementById('btn-chain-switch')"), true);
assert.equal(source.includes('if (!shouldShowPlayerChainButton())'), true);
assert.equal((source.match(/btn\.id = 'btn-chain-switch'/g) || []).length, 1);
assert.equal(source.includes('refreshChainButtonForRouteOwner'), true);
assert.equal(source.includes('window.slopsmith.on(\'audio-effects:released\', refreshChainButtonForRouteOwner);'), true);
assert.equal(source.includes('if (window._aeInjectPlayerToneButton) window._aeInjectPlayerToneButton();'), true);
assert.equal(source.includes('inspectProviderManagedAudioEffectsRoute'), true);
assert.equal(source.includes('window._aeInspectProviderManagedChain'), true);
assert.equal(source.includes('summarizeActiveProviderManagedRoute'), true);
assert.equal(source.includes('summarizeProviderManagedMappings(await fetchAudioEffectMappingsForSong(songKey)) || summarizeActiveProviderManagedRoute()'), true);
assert.equal(source.includes('window.RbMegaChain'), true);
assert.equal(source.includes("typeof rb.isPending === 'function'"), true);
assert.equal(source.includes("typeof rb.state === 'function'"), true);
assert.equal(source.includes("providerId: 'rig_builder.effects'"), true);
assert.equal(source.includes('const rigBuilderOwner = rigBuilderToneOwnershipState();'), true);
assert.equal(source.includes("['selected', 'resolving', 'resolved', 'loaded', 'degraded', 'loading', 'fallback'].includes(state)"), true);
assert.equal(source.includes("if (inspected.state === 'fallback') label = 'Chain failed'"), true);
assert.equal(source.includes("else if (inspected.state === 'degraded') label = 'Chain degraded'"), true);
assert.equal(source.includes("['selected', 'resolving', 'loading'].includes(inspected.state)"), true);
assert.equal(source.includes("'loading'") && source.includes('Loading chain'), true);
assert.equal(source.includes('Provider-managed audio-effects chain active'), true);
assert.equal(source.includes("const panelMode = providerManaged ? 'provider'"), true);
assert.equal(source.includes('if (!providerManaged && toneNamesOrdered.length > 0)'), true);
assert.equal(source.includes('if (providerChainActive) {'), true);
assert.equal(source.includes('Provider-managed audio-effects chain active — preserving chain, skipping legacy preset preload'), true);
assert.equal(source.includes('aeSetMonitorMuteSuppressed(false);'), true);
assert.equal(source.includes("['selected', 'resolving', 'loading', 'fallback'].includes(providerRoute.state)"), true);
assert.equal(source.includes('let shouldResolveChainRebuildGuard = false;'), true);
assert.equal(source.includes('if (shouldResolveChainRebuildGuard) await resolveChainRebuildGuard();'), true);
});
test('legacy midi_amp tone lookup is guarded by plugin availability', () => {
const source = readText('src/renderer/screen.js');
assert.equal(source.includes('hasMidiAmpSongTonesEndpoint'), true);
assert.equal(source.includes('midiAmpSongTonesUnavailable'), true);
assert.equal(source.includes('midiAmpSongTonesPending'), true);
assert.equal(source.includes('document.querySelector(\'[data-plugin-id="midi_amp"]\')'), true);
assert.equal(source.includes('resp.status === 404'), true);
assert.equal(source.includes('fetchMidiAmpSongTones(key)'), true);
});