gongxiangp2/app/performance-survey/PerformanceSurveyAdminPeople.test.tsx

211 lines
8.5 KiB
TypeScript

import { changeField } from '@/test-utils/select'
/** @jest-environment jsdom */
import { fireEvent, render, screen, waitFor, within } from '@testing-library/react'
import {
PerformanceSurveyAdminPeople,
type PerformanceSurveyAdminRequest,
} from './PerformanceSurveyAdminPeople'
const groups = [{
id: 'group-1',
name: '品牌设计师',
status: 'ready' as const,
memberCount: 10,
}]
function renderPeople(request: PerformanceSurveyAdminRequest) {
const onError = jest.fn()
const onSuccess = jest.fn()
render(
<PerformanceSurveyAdminPeople
month="2026-07"
groups={groups}
request={request}
onError={onError}
onSuccess={onSuccess}
/>,
)
return { onError, onSuccess }
}
describe('PerformanceSurveyAdminPeople', () => {
test('使用每页 50 人,并同时提供桌面表格和移动端卡片', async () => {
const request = jest.fn(async () => ({
items: [{
id: 'employee-1',
employeeId: 'employee-1',
displayName: '张三',
departmentPath: '集团/品牌中心',
positionTitle: '设计师',
participation: 'unassigned',
}],
total: 1,
})) as unknown as jest.MockedFunction<PerformanceSurveyAdminRequest>
renderPeople(request)
expect(screen.getByRole('status')).toHaveTextContent('正在加载人员列表')
await waitFor(() => expect(within(screen.getByTestId('people-mobile-cards')).getByText('张三')).toBeInTheDocument())
expect(screen.getByTestId('people-desktop-table')).toBeInTheDocument()
expect(screen.getByTestId('people-mobile-cards')).toBeInTheDocument()
expect(request).toHaveBeenCalledWith(expect.stringContaining('pageSize=50'))
expect(screen.getByRole('status')).toHaveTextContent('人员列表已更新,共 1 人')
})
test('选择跨页保留,并在固定批量栏一次提交全部人员', async () => {
const request = jest.fn(async (path: string, _options?: RequestInit) => {
if (path.startsWith('/admin/position-assignments?')) {
const page = new URL(path, 'https://example.test').searchParams.get('page')
return {
items: page === '2'
? [{
id: 'employee-2',
employeeId: 'employee-2',
displayName: '李四',
departmentName: '摄影中心',
positionTitle: '摄影师',
participation: 'unassigned',
}]
: [{
id: 'employee-1',
employeeId: 'employee-1',
displayName: '张三',
departmentName: '品牌中心',
positionTitle: '设计师',
participation: 'unassigned',
}],
total: 51,
}
}
return {}
}) as unknown as jest.MockedFunction<PerformanceSurveyAdminRequest>
const { onSuccess } = renderPeople(request)
await waitFor(() => expect(screen.getByLabelText('选择 张三')).toBeInTheDocument())
fireEvent.click(screen.getByLabelText('选择 张三'))
expect(screen.getByRole('region', { name: '批量分配所选人员' })).toHaveTextContent('已选择 1 人')
fireEvent.click(screen.getByRole('button', { name: '下一页' }))
await waitFor(() => expect(screen.getByLabelText('选择 李四')).toBeInTheDocument())
fireEvent.click(screen.getByLabelText('选择 李四'))
expect(screen.getByRole('region', { name: '批量分配所选人员' })).toHaveTextContent('已选择 2 人')
changeField(screen.getByLabelText('批量分配操作'), { target: { value: 'group-1' } })
expect(screen.getByPlaceholderText('本次调整原因(选填)')).toBeInTheDocument()
fireEvent.click(screen.getByRole('button', { name: '应用分配' }))
await waitFor(() => {
const call = request.mock.calls.find(([path, options]) => (
path === '/admin/position-assignments' && options?.method === 'POST'
))
expect(call).toBeDefined()
expect(JSON.parse(String(call?.[1]?.body))).toEqual(expect.objectContaining({
employeeIds: ['employee-1', 'employee-2'],
positionGroupId: 'group-1',
reason: '',
}))
})
expect(onSuccess).toHaveBeenCalledWith('已为 2 人分配岗位')
})
test('清楚区分主部门、兼任部门、职级和钉钉身份', async () => {
const request = jest.fn(async () => ({
items: [{
id: 'employee-1',
employeeId: 'employee-1',
displayName: '忆江',
departmentName: '综合支持部',
departmentPath: '集团/品牌中心/综合支持部',
departmentMemberships: [{
id: 'membership-primary',
sourceDeptId: 'dept-primary',
departmentName: '综合支持部',
departmentPath: '集团/品牌中心/综合支持部',
isPrimary: true,
syncedAt: '2026-07-27T01:00:00.000Z',
}, {
id: 'membership-photo',
sourceDeptId: 'dept-photo',
departmentName: '摄影中心',
departmentPath: '集团/摄影中心',
isPrimary: false,
syncedAt: '2026-07-27T01:00:00.000Z',
}, {
id: 'membership-support',
sourceDeptId: 'dept-support',
departmentName: '综合支持二部',
departmentPath: '集团/综合支持二部',
isPrimary: false,
syncedAt: '2026-07-27T01:00:00.000Z',
}, {
id: 'membership-ai',
sourceDeptId: 'dept-ai',
departmentName: 'AI 中心',
departmentPath: '集团/AI 中心',
isPrimary: false,
syncedAt: '2026-07-27T01:00:00.000Z',
}],
positionTitle: '视觉设计师',
positionLevel: '4',
levelType: 'P',
isLeadership: false,
isDingtalkAdmin: true,
isDingtalkBoss: false,
isDingtalkSenior: true,
participation: 'assigned',
positionGroupName: '品牌设计师',
}, {
id: 'employee-2',
employeeId: 'employee-2',
displayName: '元泽',
departmentName: '品牌中心',
positionTitle: '负责人',
positionLevel: '1',
levelType: 'M',
isLeadership: true,
isDingtalkAdmin: true,
isDingtalkBoss: true,
participation: 'assigned',
positionGroupName: '品牌管理',
}],
total: 2,
})) as unknown as jest.MockedFunction<PerformanceSurveyAdminRequest>
renderPeople(request)
const desktop = screen.getByTestId('people-desktop-table')
await waitFor(() => expect(within(desktop).getByText('忆江')).toBeInTheDocument())
expect(screen.getByPlaceholderText('姓名、部门、职位或职级')).toBeInTheDocument()
expect(within(desktop).getByText('集团/品牌中心/综合支持部')).toBeInTheDocument()
expect(within(desktop).getByText('摄影中心、综合支持二部 等 3 个部门')).toBeInTheDocument()
expect(within(desktop).getByTitle('摄影中心、综合支持二部、AI 中心')).toBeInTheDocument()
expect(within(desktop).getByText('P4')).toBeInTheDocument()
expect(within(desktop).getByText('M1')).toBeInTheDocument()
expect(within(desktop).getByText('管理岗')).toBeInTheDocument()
expect(within(desktop).getAllByText('钉钉管理员')).toHaveLength(2)
expect(within(desktop).getByText('钉钉企业负责人')).toBeInTheDocument()
expect(within(desktop).getByText('钉钉高管')).toBeInTheDocument()
const mobile = screen.getByTestId('people-mobile-cards')
expect(within(mobile).getAllByText('主部门')).toHaveLength(2)
expect(within(mobile).getByText('摄影中心、综合支持二部 等 3 个部门')).toBeInTheDocument()
expect(within(mobile).getByText('P4')).toBeInTheDocument()
expect(within(mobile).getAllByText('钉钉管理员')).toHaveLength(2)
expect(screen.queryByText('系统管理员')).not.toBeInTheDocument()
})
test('网络失败显示中文可恢复提示', async () => {
const request = jest.fn()
.mockRejectedValueOnce(new Error('Failed to fetch'))
.mockResolvedValueOnce({ items: [], total: 0 }) as unknown as jest.MockedFunction<PerformanceSurveyAdminRequest>
renderPeople(request)
expect(await screen.findByRole('alert')).toHaveTextContent('暂时无法加载人员,请检查网络后重试。')
expect(screen.queryByText('Failed to fetch')).not.toBeInTheDocument()
fireEvent.click(screen.getByRole('button', { name: '重新加载' }))
await waitFor(() => expect(screen.getByRole('status')).toHaveTextContent('人员列表已更新,共 0 人'))
})
})