import { render, fireEvent } from '@testing-library/react'; import { beforeEach, describe, expect, it } from 'vitest'; import Sidebar from '../../src/components/Sidebar'; import { useUIStore } from '../../src/stores/uiStore'; import { useAuthStore } from '../../src/stores/authStore'; import { useMailStore } from '../../src/stores/mailStore'; import { useContactStore } from '../../src/stores/contactStore'; /* * 侧栏导航**点了要去对地方**。 * * 这个判据是补写的:用户报「侧边导航栏完全不可用,点击无法翻页」—— * 根因是「通信」合并成一项后我写成 `setViewMode(target || commTab || modes[0])`, * 而日历/联系人没有 `target` ⇒ 点它们会跳到 `commTab`(收件箱)。 * * 我当时的验证只看了 DOM 结构与样式(导航项数、徽标、圆角、玻璃), * **一次都没点过**,所以这个 bug 一路到了线上。结构类判据必须配一条"点它"的判据。 */ describe('侧栏导航点击目标', () => { let view: ReturnType; beforeEach(() => { useUIStore.getState().reset(); useAuthStore.setState({ user: { username: 'gui-lab', role: 'admin' } as never }); useMailStore.setState({ inbox: [] }); useContactStore.setState({ contacts: [] }); view = render(); }); // 按**可见文字**找按钮(不用 getByTitle:title 属性在这个环境里查不到, // 而按钮文字就是用户点的东西 —— 判据要贴住用户实际看到的那一层) const click = (label: string) => { const btn = [...document.querySelectorAll('button')].find(b => (b.textContent || '').trim() === label ); if (!btn) throw new Error(`找不到导航项:${label}(现有:${[...document.querySelectorAll('button')].map(b => b.textContent?.trim()).join('/')})`); fireEvent.click(btn); return useUIStore.getState().viewMode; }; it('点「日历」去日历(不是回通信)', () => { expect(click('日历')).toBe('calendar'); }); it('点「联系」去联系人', () => { expect(click('联系')).toBe('contacts'); }); it('点「通信」去通信上次用的子页签', () => { // ★ 改 store 之后必须**重新渲染**再点:否则组件的点击闭包里还是旧的 commTab // (我第一版没 rerender,拿到 'inbox',差点误判成代码有问题)。 // 这里也说明了另一件事:内部页签渲染在 App 里而不是 Sidebar 里, // 所以 Sidebar 的单测无法通过"点页签"来设置它。 useUIStore.getState().setViewMode('sent'); view.rerender(); expect(click('通信')).toBe('sent'); }); it('★ 反向对照:从日历点「通信」不会停在日历', () => { useUIStore.getState().setViewMode('calendar'); expect(click('通信')).toBe('inbox'); }); });