121 lines
3.9 KiB
TypeScript
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'))
|
|
})
|
|
})
|