211 lines
8.5 KiB
TypeScript
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 人'))
|
|
})
|
|
})
|