app-sidebar.test.tsx 2.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. import { act, fireEvent, screen } from '@testing-library/react';
  2. import { MemoryRouter } from 'react-router';
  3. import { afterEach, expect, test, vi } from 'vitest';
  4. import AppSidebar from '@/layouts/AppSidebar';
  5. import { renderWithProviders } from './test-utils';
  6. vi.mock('@/api/queries/useAllSettings', () => ({
  7. useAllSettings: () => ({ allSetting: {} }),
  8. }));
  9. afterEach(() => {
  10. localStorage.clear();
  11. });
  12. // rc-menu registers its items in a microtask after render; settle it inside act().
  13. async function renderSidebar() {
  14. const view = renderWithProviders(
  15. <MemoryRouter>
  16. <AppSidebar />
  17. </MemoryRouter>,
  18. );
  19. await act(async () => {});
  20. return view;
  21. }
  22. test('keeps the sidebar expanded after pinning it from the header and restores the choice', async () => {
  23. const first = await renderSidebar();
  24. const sidebar = first.container.querySelector('.ant-layout-sider');
  25. const sidebarRoot = first.container.querySelector('.ant-sidebar');
  26. expect(sidebar?.classList.contains('ant-layout-sider-collapsed')).toBe(true);
  27. fireEvent.mouseEnter(sidebarRoot!);
  28. const pinButton = screen.getByRole('button', { name: 'Pin sidebar' });
  29. expect(pinButton.closest('.brand-actions')).not.toBeNull();
  30. fireEvent.click(pinButton);
  31. fireEvent.mouseLeave(sidebarRoot!);
  32. expect(sidebar?.classList.contains('ant-layout-sider-collapsed')).toBe(false);
  33. expect(sidebarRoot?.getAttribute('style')).toContain('--sider-rail: 220px');
  34. expect(localStorage.getItem('sidebar-pinned')).toBe('true');
  35. first.unmount();
  36. const second = await renderSidebar();
  37. const restoredSidebar = second.container.querySelector('.ant-layout-sider');
  38. const restoredSidebarRoot = second.container.querySelector('.ant-sidebar');
  39. expect(restoredSidebar?.classList.contains('ant-layout-sider-collapsed')).toBe(false);
  40. expect(restoredSidebarRoot?.getAttribute('style')).toContain('--sider-rail: 220px');
  41. expect(screen.getByRole('button', { name: 'Pin sidebar' })).not.toBeNull();
  42. });
  43. test('returns to the compact rail after unpinning', async () => {
  44. const view = await renderSidebar();
  45. const sidebar = view.container.querySelector('.ant-layout-sider');
  46. const sidebarRoot = view.container.querySelector('.ant-sidebar');
  47. fireEvent.mouseEnter(sidebarRoot!);
  48. fireEvent.click(screen.getByRole('button', { name: 'Pin sidebar' }));
  49. fireEvent.click(screen.getByRole('button', { name: 'Pin sidebar' }));
  50. fireEvent.mouseLeave(sidebarRoot!);
  51. expect(sidebar?.classList.contains('ant-layout-sider-collapsed')).toBe(true);
  52. expect(sidebarRoot?.getAttribute('style')).toContain('--sider-rail: 72px');
  53. expect(localStorage.getItem('sidebar-pinned')).toBe('false');
  54. });
  55. test('labels the palette shortcut with the modifier the platform actually uses', async () => {
  56. const view = await renderSidebar();
  57. const chip = view.container.querySelector('.sidebar-command-kbd');
  58. expect(chip?.textContent).toBe('CtrlK');
  59. });