gongxiangp2/lib/__tests__/work-review-board.test.tsx
2026-08-05 16:49:54 +08:00

121 lines
3.9 KiB
TypeScript

/** @jest-environment jsdom */
import { fireEvent, render, screen, waitFor } from '@testing-library/react'
import WorkReviewBoard from '@/components/work-review/WorkReviewBoard'
import { deleteWorkReviewProject, getWorkReviewBoard } from '@/lib/work-review-client'
import type { WorkReviewBoardData } from '@/types/work-review'
const replace = jest.fn()
let searchParamsValue = 'project=project-1'
jest.mock('next/navigation', () => ({
useRouter: () => ({ replace }),
useSearchParams: () => new URLSearchParams(searchParamsValue),
}))
jest.mock('next-auth/react', () => ({
useSession: () => ({
data: {
user: { id: 'user-1', name: '无邪' },
expires: '2099-01-01T00:00:00.000Z',
},
status: 'authenticated',
}),
}))
jest.mock('@/lib/work-review-client', () => ({
getWorkReviewBoard: jest.fn(),
createWorkReviewProject: jest.fn(),
createWorkReviewVersion: jest.fn(),
deleteWorkReviewProject: jest.fn(),
submitWorkReview: jest.fn(),
WorkReviewRequestError: class WorkReviewRequestError extends Error {
status = 500
},
}))
jest.mock('@/components/work-review/WorkReviewReviewerWorkspace', () => ({
WorkReviewReviewerWorkspace: ({ project }: { project: { title: string } }) => (
<div data-testid="shared-work-review-workspace">{project.title}</div>
),
}))
const boardData: WorkReviewBoardData = {
me: {
user: { id: 'user-1', name: '无邪', avatar: null, role: 'user' },
employee: {
id: 'submitter-1',
displayName: '无邪',
},
permissions: {
canSubmit: true,
canDeleteProjects: true,
isSystemAdmin: false,
isManager: false,
isFinalReviewer: false,
},
},
items: [{
id: 'project-1',
title: '普通双评审作品',
description: '作品说明',
workDate: '2026-08-01',
status: 'pending_review',
latestVersion: 1,
submitter: { id: 'submitter-1', name: '无邪' },
manager: { id: 'manager-1', name: '魔礼红' },
finalReviewer: { id: 'final-1', name: '元泽' },
createdAt: '2026-08-01T00:00:00.000Z',
updatedAt: '2026-08-01T00:00:00.000Z',
reviewMode: 'dual',
requiredReviewRoles: ['manager', 'final_reviewer'],
versions: [{
id: 'version-1',
version: 1,
submissionNote: null,
status: 'pending_review',
submittedAt: '2026-08-01T00:00:00.000Z',
completedAt: null,
imageUrls: [],
imageGroups: [],
referenceImageUrls: [],
referenceImageGroups: [],
reviews: [],
}],
permissions: {
canResubmit: false,
pendingReviewRoles: [],
},
}],
pagination: { page: 1, pageSize: 20, total: 1, totalPages: 1 },
}
describe('WorkReviewBoard', () => {
beforeEach(() => {
replace.mockReset()
searchParamsValue = 'project=project-1'
;(getWorkReviewBoard as jest.Mock).mockResolvedValue(boardData)
;(deleteWorkReviewProject as jest.Mock).mockResolvedValue({ id: 'project-1', title: '普通双评审作品' })
})
test('opens the shared detail workspace for a visible submitter project without review permission', async () => {
render(<WorkReviewBoard />)
await waitFor(() => expect(screen.getByTestId('shared-work-review-workspace')).toHaveTextContent('普通双评审作品'))
expect(screen.queryByText('作品与评审记录')).not.toBeInTheDocument()
})
test('asks for confirmation before deleting a project from the board', async () => {
searchParamsValue = ''
render(<WorkReviewBoard />)
const deleteButton = await screen.findByRole('button', { name: '删除作品:普通双评审作品' })
fireEvent.click(deleteButton)
expect(screen.getByRole('dialog', { name: '删除作品' })).toBeInTheDocument()
expect(deleteWorkReviewProject).not.toHaveBeenCalled()
fireEvent.click(screen.getByRole('button', { name: '确认删除' }))
await waitFor(() => expect(deleteWorkReviewProject).toHaveBeenCalledWith('project-1'))
})
})