/** * Fallback switcher integration test. * * If the shipped controls never upgrade — a blocked module load, an older bundle, a * proxy hiccup — the admin falls back to `LegacyThemeSwitcher`. This test keeps that * path genuinely usable: the theme dropdown must always be present (even in the admin * chrome), and choosing a theme or toggling light/dark must apply the document * attributes the preview stylesheet is scoped to and persist the choice. * * It renders the REAL `ThemeSwitcher` under the REAL `AdminThemeProvider` with * `loadRuntimeControls` mocked to never resolve, so `controlsReady` stays false and the * fallback is what renders. */ import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest' import { fireEvent, render, screen, waitFor } from '@testing-library/react' import { QueryClient, QueryClientProvider } from '@tanstack/react-query' import { AdminThemeProvider } from './admin-theme' import { ThemeSwitcher } from './shell' vi.mock('../lib/runtime-controls', () => ({ // Never resolves: the shipped controls never upgrade, so the fallback stays in place. loadRuntimeControls: () => new Promise(() => undefined), })) vi.mock('../lib/api', () => ({ getManifest: vi.fn(() => Promise.resolve({ apiVersion: '1', baseUrl: '/rt/v1', themes: [] })), getSession: vi.fn(() => Promise.resolve({ authenticated: true, mode: 'dev' })), updatePreferences: vi.fn(() => Promise.resolve({ selectedTheme: '', selectedAppearance: '' })), resetPreferences: vi.fn(() => Promise.resolve({ selectedTheme: '', selectedAppearance: '' })), })) const api = await import('../lib/api') const THEME_ATTR = 'data-bananas-theme' const APPEARANCE_ATTR = 'data-bananas-appearance' function renderSwitcher() { const client = new QueryClient({ defaultOptions: { queries: { retry: false, gcTime: 0 } } }) return render( , ) } // The dropdown is populated from the runtime manifest, which arrives asynchronously. A // controlled