import { fireEvent, render, screen, waitFor } from '@testing-library/react' import { HelmetProvider } from 'react-helmet-async' import { beforeEach, describe, expect, it, vi } from 'vitest' import SidebarComponent from '@/components/layout/SidebarComponent' const sidebarWidth = (element: Element | null): string => (element as HTMLElement).style.getPropertyValue ('--sidebar-width') const sidebarRoot = (container: HTMLElement): Element => container.querySelector ('[style*="--sidebar-width"]')! const sidebarTree = (props: Partial[0]>) => (
Sidebar body
) const renderSidebar = ( props: Partial[0]> = {}, containerWidth = 800, ) => { Object.defineProperty (HTMLElement.prototype, 'clientWidth', { configurable: true, get () { return this.hasAttribute ('data-sidebar-container') ? containerWidth : 0 }, }) const rendered = render (sidebarTree (props)) return rendered } describe ('SidebarComponent', () => { beforeEach (() => { Object.defineProperty (window, 'innerWidth', { configurable: true, value: 1_000, }) Object.defineProperty (HTMLElement.prototype, 'setPointerCapture', { configurable: true, value: vi.fn (), }) Object.defineProperty (HTMLElement.prototype, 'releasePointerCapture', { configurable: true, value: vi.fn (), }) Object.defineProperty (HTMLElement.prototype, 'hasPointerCapture', { configurable: true, value: vi.fn (() => true), }) vi.spyOn (HTMLElement.prototype, 'setPointerCapture').mockImplementation (() => { ; }) vi.spyOn (HTMLElement.prototype, 'releasePointerCapture').mockImplementation (() => { ; }) vi.spyOn (HTMLElement.prototype, 'hasPointerCapture').mockReturnValue (true) }) it ('uses maxWidth without applying the container main-width reserve twice', async () => { localStorage.setItem ('sidebar:test-sidebar:left:width', '700') const onWidthChange = vi.fn () const { container } = renderSidebar ({ maxWidth: 700, onWidthChange }, 800) await waitFor (() => { expect (sidebarWidth (sidebarRoot (container))).toBe ('700px') }) expect (onWidthChange).toHaveBeenLastCalledWith (700) }) it ('resets width and removes only its storage key on double click', async () => { localStorage.setItem ('sidebar:test-sidebar:right:width', '420') localStorage.setItem ('sidebar:other-sidebar:right:width', '480') const { container } = renderSidebar ({ side: 'right' }, 900) await waitFor (() => { expect (sidebarWidth (sidebarRoot (container))).toBe ('420px') }) fireEvent.doubleClick (screen.getByRole ('separator', { name: 'サイドバー幅' })) await waitFor (() => { expect (sidebarWidth (sidebarRoot (container))).toBe ('256px') }) expect (localStorage.getItem ('sidebar:test-sidebar:right:width')).toBeNull () expect (localStorage.getItem ('sidebar:other-sidebar:right:width')).toBe ('480') }) it ('clamps current width on maxWidth changes without re-reading storage', async () => { localStorage.setItem ('sidebar:test-sidebar:left:width', '420') const { container, rerender } = renderSidebar ({ maxWidth: 420 }, 900) await waitFor (() => { expect (sidebarWidth (sidebarRoot (container))).toBe ('420px') }) rerender (sidebarTree ({ maxWidth: 300 })) await waitFor (() => { expect (sidebarWidth (sidebarRoot (container))).toBe ('300px') }) rerender (sidebarTree ({ maxWidth: 500 })) await waitFor (() => { expect (sidebarWidth (sidebarRoot (container))).toBe ('300px') }) }) })