import { describe, test, expect, vi } from 'vitest'; import React from 'react'; import { createRoot, Root } from 'react-dom/client'; import { act } from 'react-dom/test-utils'; import { MobilePanelBar } from './MobilePanelBar'; import { MobileChromeProvider } from '../../state/MobileChromeContext'; /** * Mobile-A2 (review item 5): the real BlocksPanel/PagesPanel/LayersPanel/ * AssetsPanel/GuidedStyles all pull in Craft.js's `useEditor` and other * heavy dependencies not relevant here, so they're stubbed out -- this * suite is only exercising MobilePanelBar's OWN wiring: tapping a tab opens * that tab's sheet with only its panel rendered, tapping the active tab * again closes it, and (mirroring MobileChromeContext.test.tsx) only one * sheet's content is ever mounted at once. */ vi.mock('../left/BlocksPanel', () => ({ BlocksPanel: () =>
})); vi.mock('../left/PagesPanel', () => ({ PagesPanel: () =>
})); vi.mock('../left/LayersPanel', () => ({ LayersPanel: () =>
})); vi.mock('../left/AssetsPanel', () => ({ AssetsPanel: () =>
})); vi.mock('../right/GuidedStyles', () => ({ GuidedStyles: () =>
})); let container: HTMLDivElement; let root: Root; function render(ui: React.ReactElement) { container = document.createElement('div'); document.body.appendChild(container); act(() => { root = createRoot(container); root.render(ui); }); } function unmount() { act(() => { root.unmount(); }); container.remove(); } function tabButton(label: string): HTMLButtonElement { const buttons = Array.from(container.querySelectorAll('.mobile-tab-btn')) as HTMLButtonElement[]; const btn = buttons.find((b) => b.textContent?.includes(label)); if (!btn) throw new Error(`No tab button found for "${label}"`); return btn; } function openPanelIds(): string[] { return Array.from(container.querySelectorAll('[data-testid^="panel-"]')).map( (el) => (el as HTMLElement).dataset.testid!, ); } describe('MobilePanelBar', () => { test('no sheet is open initially', () => { render( , ); expect(container.querySelector('.mobile-sheet-backdrop')).toBeNull(); expect(openPanelIds()).toEqual([]); unmount(); }); test('tapping a tab opens exactly that tab\'s panel', () => { render( , ); act(() => { tabButton('Blocks').click(); }); expect(openPanelIds()).toEqual(['panel-blocks']); unmount(); }); test('switching tabs replaces the open sheet -- only one panel mounted at a time', () => { render( , ); act(() => { tabButton('Blocks').click(); }); expect(openPanelIds()).toEqual(['panel-blocks']); act(() => { tabButton('Styles').click(); }); expect(openPanelIds()).toEqual(['panel-styles']); act(() => { tabButton('Assets').click(); }); expect(openPanelIds()).toEqual(['panel-assets']); unmount(); }); test('tapping the active tab again closes the sheet', () => { render( , ); act(() => { tabButton('Pages').click(); }); expect(openPanelIds()).toEqual(['panel-pages']); expect(container.querySelector('.mobile-sheet-backdrop')).not.toBeNull(); act(() => { tabButton('Pages').click(); }); expect(openPanelIds()).toEqual([]); expect(container.querySelector('.mobile-sheet-backdrop')).toBeNull(); unmount(); }); test('active tab button carries aria-pressed=true only for the open sheet', () => { render( , ); act(() => { tabButton('Layers').click(); }); expect(tabButton('Layers').getAttribute('aria-pressed')).toBe('true'); expect(tabButton('Blocks').getAttribute('aria-pressed')).toBe('false'); unmount(); }); });