import { fireEvent, render } from '@testing-library/react'; import { act } from 'react'; import { beforeEach, describe, expect, it, vi } from 'vitest'; import { RightSidebarProvider, useRightSidebar, } from '../../src/contexts/RightSidebarContext'; type RightSidebarHarnessOptions = { pathname?: string; onMobileOpenRequest?: () => void; }; function setViewportWidth(width: number) { Object.defineProperty(window, 'innerWidth', { configurable: true, writable: true, value: width, }); Object.defineProperty(window, 'matchMedia', { configurable: true, writable: true, value: undefined, }); } function renderRightSidebarHarness(options: RightSidebarHarnessOptions = {}) { const { pathname = '/users', onMobileOpenRequest } = options; let currentPathname = pathname; let currentValue: ReturnType | null = null; function Probe() { currentValue = useRightSidebar(); return null; } function Wrapper({ pathname }: Readonly<{ pathname: string }>) { return ( ); } const rendered = render(); return { getCurrent() { if (!currentValue) { throw new Error('Right sidebar context value not initialized'); } return currentValue; }, reroute(nextPathname: string) { currentPathname = nextPathname; rendered.rerender(); }, unmount: rendered.unmount, }; } describe('RightSidebarContext', () => { beforeEach(() => { localStorage.removeItem('authRightSidebarWidth'); setViewportWidth(1024); }); it('throws when useRightSidebar is used outside provider', () => { function Invalid() { useRightSidebar(); return null; } expect(() => render()).toThrow('useRightSidebar must be used within RightSidebarProvider'); }); it('opens and closes with content', () => { const harness = renderRightSidebarHarness({ pathname: '/users' }); act(() => { harness.getCurrent().openSidebar({ title: 'Meta', content:
Body
, }); }); expect(harness.getCurrent().isOpen).toBe(true); expect(harness.getCurrent().content?.title).toBe('Meta'); act(() => { harness.getCurrent().closeSidebar(); }); expect(harness.getCurrent().isOpen).toBe(false); expect(harness.getCurrent().content).toBeNull(); }); it('does not open without current or next content', () => { const harness = renderRightSidebarHarness({ pathname: '/users' }); act(() => { harness.getCurrent().openSidebar(); }); expect(harness.getCurrent().isOpen).toBe(false); expect(harness.getCurrent().content).toBeNull(); }); it('updates content live and supports toggle semantics', () => { const harness = renderRightSidebarHarness({ pathname: '/users' }); act(() => { harness.getCurrent().openSidebar({ title: 'Meta', content:
Body
, }); }); act(() => { harness.getCurrent().setSidebarContent({ title: 'Meta Updated', content:
Updated
, }); }); expect(harness.getCurrent().isOpen).toBe(true); expect(harness.getCurrent().content?.title).toBe('Meta Updated'); act(() => { harness.getCurrent().toggleSidebar(); }); expect(harness.getCurrent().isOpen).toBe(false); expect(harness.getCurrent().content).toBeNull(); }); it('toggleSidebar opens with provided content when closed', () => { const harness = renderRightSidebarHarness({ pathname: '/users' }); act(() => { harness.getCurrent().toggleSidebar({ title: 'Toggle open', content:
Toggle body
, }); }); expect(harness.getCurrent().isOpen).toBe(true); expect(harness.getCurrent().content?.title).toBe('Toggle open'); }); it('closes on pathname changes', () => { const harness = renderRightSidebarHarness({ pathname: '/users' }); act(() => { harness.getCurrent().openSidebar({ title: 'Meta', content:
Body
, }); }); expect(harness.getCurrent().isOpen).toBe(true); harness.reroute('/posts'); expect(harness.getCurrent().isOpen).toBe(false); expect(harness.getCurrent().content).toBeNull(); }); it('reads/clamps persisted width, persists resized widths, and reacts to escape', async () => { localStorage.setItem('authRightSidebarWidth', '999'); const harness = renderRightSidebarHarness({ pathname: '/users' }); expect(harness.getCurrent().desktopSidebarStyle['--auth-right-sidebar-width']).toBe( '480px', ); act(() => { harness.getCurrent().openSidebar({ title: 'Meta', content:
Body
, }); }); const preventDefault = vi.fn(); act(() => { harness.getCurrent().startResize({ clientX: 480, preventDefault, } as never); }); act(() => { fireEvent.pointerMove(window, { clientX: -400 }); fireEvent.pointerUp(window); }); await act(async () => { await Promise.resolve(); }); expect(preventDefault).toHaveBeenCalledTimes(1); expect(localStorage.getItem('authRightSidebarWidth')).toBe('480'); act(() => { fireEvent.keyDown(window, { key: 'Escape' }); }); expect(harness.getCurrent().isOpen).toBe(false); }); it('notifies mobile open requests when opening on mobile', () => { setViewportWidth(768); const onMobileOpenRequest = vi.fn(); const harness = renderRightSidebarHarness({ pathname: '/users', onMobileOpenRequest, }); act(() => { harness.getCurrent().openSidebar({ title: 'Meta', content:
Body
, }); }); expect(harness.getCurrent().isOpen).toBe(true); expect(onMobileOpenRequest).toHaveBeenCalledTimes(1); }); it('normalizes custom sizing values', () => { function Probe() { const sidebar = useRightSidebar(); return
{sidebar.desktopSidebarStyle['--auth-right-sidebar-width']}
; } const { getByTestId } = render( , ); expect(getByTestId('width').textContent).toBe('500px'); }); });