AdmSysV2【公共组件库】@前端(For Git Submodule)
Tevin
2 days ago 9f6212d61eba53eb4da504876f5a01b93a80fc1c
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen } from '@testing-library/react';
import React from 'react';
import { CSideMenu } from '../../src/framework/sideMenu/CSideMenu';
 
// Mock window.matchMedia
Object.defineProperty(window, 'matchMedia', {
  writable: true,
  value: vi.fn().mockImplementation((query: string) => ({
    matches: false,
    media: query,
    onchange: null,
    addEventListener: vi.fn(),
    removeEventListener: vi.fn(),
    dispatchEvent: vi.fn(),
  })),
});
 
// Mock antd Menu component
vi.mock('antd', async () => {
  const actual = await vi.importActual('antd');
  return {
    ...actual,
    Menu: vi.fn(({ items, onClick, selectedKeys, openKeys, onOpenChange, children }) => {
      // Render items as a nested structure for testing
      const renderItems = (items: any[]): React.ReactNode =>
        items?.map((item) => (
          <div key={item.key} data-testid={`menu-item-${item.key}`}>
            {item.label}
            {item.children && <div className="submenu">{renderItems(item.children)}</div>}
          </div>
        ));
      return <div data-testid="antd-menu">{items ? renderItems(items) : children}</div>;
    }),
    Layout: {
      Sider: vi.fn(({ children, breakpoint, onBreakpointChange }) => children),
    },
  };
});
 
// Mock icons
vi.mock('@ant-design/icons', () => ({
  PieChartOutlined: () => <span data-testid="icon-chart">ChartIcon</span>,
  SettingOutlined: () => <span data-testid="icon-setting">SettingIcon</span>,
  FolderOutlined: () => <span data-testid="icon-folder">FolderIcon</span>,
  FileOutlined: () => <span data-testid="icon-file">FileIcon</span>,
  RightOutlined: () => <span data-testid="icon-right">RightIcon</span>,
}));
 
describe('CSideMenu 组件', () => {
  const mockOnClickMenuItem = vi.fn();
  const mockOnSetMenuCollapse = vi.fn();
 
  const basicTree = {
    key: '1',
    label: '导航1',
    children: [
      {
        key: '1-1',
        label: '子菜单1-1',
        children: [
          { key: '1-1-1', label: '页面1-1-1', path: '/page1-1-1', pageName: 'Page111' },
          { key: '1-1-2', label: '页面1-1-2', path: '/page1-1-2', pageName: 'Page112' },
        ],
      },
      {
        key: '1-2',
        label: '页面1-2',
        path: '/page1-2',
        pageName: 'Page12',
      },
    ],
  };
 
  beforeEach(() => {
    vi.clearAllMocks();
  });
 
  describe('基础渲染', () => {
    it('1.1 渲染空树时不报错', () => {
      render(
        <CSideMenu
          title="测试标题"
          tree={undefined as any}
          collapsed={false}
          onClickMenuItem={mockOnClickMenuItem}
          onSetMenuCollapse={mockOnSetMenuCollapse}
        />
      );
      expect(screen.getByText('测试标题')).toBeDefined();
    });
 
    it('1.2 渲染标题', () => {
      render(
        <CSideMenu
          title="我的侧边栏"
          tree={basicTree}
          collapsed={false}
          onClickMenuItem={mockOnClickMenuItem}
          onSetMenuCollapse={mockOnSetMenuCollapse}
        />
      );
      expect(screen.getByText('我的侧边栏')).toBeDefined();
    });
  });
 
  describe('三级菜单渲染', () => {
    it('3.1 渲染三级菜单结构', () => {
      render(
        <CSideMenu
          title="测试"
          tree={basicTree}
          collapsed={false}
          onClickMenuItem={mockOnClickMenuItem}
          onSetMenuCollapse={mockOnSetMenuCollapse}
        />
      );
      expect(screen.getByText('导航1')).toBeDefined();
      expect(screen.getByText('子菜单1-1')).toBeDefined();
      expect(screen.getByText('页面1-1-1')).toBeDefined();
    });
  });
});