// REQ-USR-001 / REQ-USR-002: UserDetailToolbar 工具栏单测(保存/取消/新增 + 提交中禁用 + 占位按钮,BR12/BR13/BR14/BR15/D8) import { describe, it, expect, vi, beforeEach } from 'vitest'; import { screen } from '@testing-library/react'; import userEvent from '@testing-library/user-event'; const messageSpy = { success: vi.fn(), error: vi.fn(), warning: vi.fn(), info: vi.fn() }; vi.mock('antd', async () => { const actual = await vi.importActual('antd'); return { ...actual, App: Object.assign(actual.App, { useApp: () => ({ message: messageSpy }) }), }; }); import { renderShell } from './renderShell'; import UserDetailToolbar from '../../src/pages/usr/UserDetail/UserDetailToolbar'; function setup(over: { mode?: 'create' | 'edit'; submitting?: boolean; canSave?: boolean } = {}) { const onSave = vi.fn(); const onCancel = vi.fn(); const onNew = vi.fn(); renderShell( , { preloadedAuth: { token: 't', user: { id: 1, sUserName: 'a', sUserType: 'x', sLanguage: '中文' } } }, ); return { onSave, onCancel, onNew }; } describe('UserDetailToolbar', () => { beforeEach(() => { vi.clearAllMocks(); }); it('renders 保存/取消/新增 + placeholder buttons + gear', () => { setup(); expect(screen.getByTestId('btn-save')).toBeInTheDocument(); expect(screen.getByTestId('btn-cancel')).toBeInTheDocument(); expect(screen.getByTestId('btn-new')).toBeInTheDocument(); expect(screen.getByText('删除')).toBeInTheDocument(); expect(screen.getByText('作废')).toBeInTheDocument(); expect(screen.getByText('重置密码')).toBeInTheDocument(); expect(screen.getByText('取消作废')).toBeInTheDocument(); expect(screen.getByText('功能')).toBeInTheDocument(); expect(screen.getByTestId('btn-gear')).toBeInTheDocument(); }); it('click 保存 calls onSave / 取消 calls onCancel / 新增 calls onNew', async () => { const user = userEvent.setup(); const { onSave, onCancel, onNew } = setup(); await user.click(screen.getByTestId('btn-save')); expect(onSave).toHaveBeenCalledTimes(1); await user.click(screen.getByTestId('btn-cancel')); expect(onCancel).toHaveBeenCalledTimes(1); await user.click(screen.getByTestId('btn-new')); expect(onNew).toHaveBeenCalledTimes(1); }); it('submitting disables 保存 and shows loading', async () => { const user = userEvent.setup(); const { onSave } = setup({ submitting: true }); const btn = screen.getByTestId('btn-save'); expect(btn).toBeDisabled(); await user.click(btn); expect(onSave).not.toHaveBeenCalled(); }); it('canSave=false disables 保存', () => { setup({ canSave: false }); expect(screen.getByTestId('btn-save')).toBeDisabled(); }); it('placeholder buttons show 功能开发中 (no business callback)', async () => { const user = userEvent.setup(); const { onSave, onCancel, onNew } = setup(); await user.click(screen.getByText('删除')); expect(messageSpy.info).toHaveBeenCalledWith('功能开发中'); await user.click(screen.getByTestId('btn-gear')); expect(messageSpy.info).toHaveBeenCalledWith('功能开发中'); expect(onSave).not.toHaveBeenCalled(); expect(onCancel).not.toHaveBeenCalled(); expect(onNew).not.toHaveBeenCalled(); }); });